挂面09

作者: 盼旺 | 来源:发表于2019-10-15 22:30 被阅读0次

1.使用list队列/wait()/notify()实现生产者消费者

其中一种是通过阻塞队列(BlockingQueue)来进行,直接可以创建多个线程去进行操作即可,不需要对方法额外进行同步,
还有一种就是本文的通过wait()与notify()来进行操作。

wait():进入临界区的线程在运行到一部分后,发现进行后面的任务所需的资源还没有准备充分,所以调用wait()方法,让线程阻塞,等待资源,同时释放临界区的锁,此时线程的状态也从运行状态变为等待状态;

notify():准备资源的线程在准备好资源后,调用notify()方法通知需要使用资源的线程,同时释放临界区的锁,将临界区的锁交给使用资源的线程。

wait()、notify()这两个方法,都必须要在临界区中调用,即是在synchronized同步块中调用,不然会抛出IllegalMonitorStateException的异常。
临界区指的是一个访问共用资源的程序片段,而这些共用资源又无法同时被多个线程访问的特性。
实现

通过一个List对对象进行储存,消费者从List中取对象进行消费。在List为空时,消费者线程执行wait操作,让生产者获取到对象,在生产好对象后,再通过notify唤醒消费者线程进行消费

import java.util.ArrayList;
import java.util.List;

public class ThreadTest {
    private static List list = new ArrayList();
    private static int len = 2;
    int id;
    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        Thread prodecer1 = new Thread(threadTest.new Producer(), "生产者1");
        Thread consumer1= new Thread(threadTest.new Custemer(), "消费者1");
        Thread consumer2 = new Thread(threadTest.new Custemer(), "消费者2");
        prodecer1.start();
        consumer1.start();
        consumer2.start();
        return;
    }
    //生产者
    private class Producer implements Runnable{
        @Override
        public void run() {
            while (true){
                synchronized (list){
                    if(list.size()>=len){
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    list.add(id++);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" 生产了");
                    System.out.println(list.size());
                    list.notifyAll();
                }
            }
        }
    }
    //消费者
    private class Custemer implements Runnable{

        @Override
        public void run() {
            while (true){
                synchronized (list){
                    while (list.size()==0){//注意这里不能为if因为下面说明
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    list.remove(0);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" 消费了");
                    System.out.println(list.size());
                    list.notify();
                }
            }
        }
    }
}

为if的话判断一次
一号消费者尝试进行消费,发现数组为空,所以通过wait释放了资源,然后生产者进行生产。在生产者生产完成后,通过了notifyAll通知所有线程资源准备好了,这时二号消费者首先抢到了资源,顺利的进行消费,数组这时就为空,之后唤醒一号消费者,这时一号消费者并不知道数组中没有产品,所以进行操作,就会抛出数组越界的错误

2.HTTP 和 HTTPS

端口
HTTP 的 URL 由 http:// 起始,且默认端口为 80;
而 HTTPS 的 URL 由 https:// 起始,默认使用端口 443;
安全性和资源消
HTTP 协议直接运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。
HTTPS 是运行在 SSL/TLS 之上的 HTTP 协议,SSL/TLS 又运行在 TCP 之上,所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥由服务器方的证书进行了非对称加密。
所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源。

对称加密:密钥只有一个,加密解密为同一个密码,且加解密速度快,典型的对称加密算法有 DES、AES 等;
非对称加密:密钥成对出现(且根据公钥无法推知私钥,根据私钥也无法推知公钥),加密解密使用不同密钥(公钥加密需要私钥解密,私钥加密需要公钥解密),对比对称加密,速度较慢,典型的非对称加密算法有 RSA、DSA 等。

3.HTTP 长连接 && 短连接

在 HTTP/1.0 中默认使用短连接,也就是说,客户端和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接;

而从 HTTP/1.1 起,默认使用长连接,用以保持连接特性,使用长连接的 HTTP 协议,会在响应头加入这行代码:Connection: keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这条已建立的连接,Keep-Alive 不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如 Apache、Nginx)中设定这个时间,实现长连接需要客户端和服务端都配置支持;

HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接

4.Java中默认的访问权限作用域

作用域 当前类 同一包(package) 子类 其他包
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N

普通类的默认访问权限是 **default **
默认不写的时候 子类不能访问 但为啥我子类还能调用父类的变量 是因为当前子类在本包中给大家测试个例子就清楚了

关于抽象类
JDK 1.8以前,抽象类的方法默认访问权限为protected
JDK 1.8时,抽象类的方法默认访问权限变为default
关于接口
JDK 1.8以前,接口中的方法必须是public的
JDK 1.8时,接口中的方法可以是public的,也可以是default的
JDK 1.9时,接口中的方法可以是private的

5.Java中的Lock接口,比起synchronized,优势在哪里?

如果需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,如何实现?
Lock接口较大的优势是为读和写分别提供了锁。
读写锁ReadWriteLock拥有更加强大的功能,它可细分为读锁和解锁。
读锁可以允许多个进行读操作的线程同时进入,但不允许写进程进入;写锁只允许一个写进程进入,在这期间任何进程都不能再进入。(完全符合题目中允许多个用户读和一个用户写的条件)
要注意的是每个读写锁都有挂锁和解锁,较好将每一对挂锁和解锁操作都用try、finally来套入中间的代码,这样就会防止因异常的发生而造成死锁得情况。
下面是一个示例程序:

import java.util.concurrent.locks.*;
public class ReadWriteLockTest {
public static void main(String[] args) {
 final TheData myData=new TheData();  //这是各线程的共享数据
  for(int i=0;i<3;i++){ //开启3个读线程
  new Thread(new Runnable(){
  @Override
  public void run() {
    while(true){
       myData.get();
    }
}}).start();
}

  for(int i=0;i<3;i++){ //开启3个写线程
  new Thread(new Runnable(){
  @Override
  public void run() {

  while(true){
  myData.put(new Random().nextInt(10000));
  }
  }
  }).start();
 }
  }
  }
  class TheData{
  private Object data=null;
  private ReadWriteLock rwl=new ReentrantReadWriteLock();
  public void get(){
  rwl.readLock().lock();  //读锁开启,读线程均可进入
  try { //用try finally来防止因异常而造成的死锁
  System.out.println(Thread.currentThread().getName()+"is ready to read");
  Thread.sleep(new Random().nextInt(100));
  System.out.println(Thread.currentThread().getName()+"have read date"+data);
  } catch (InterruptedException e) {
  e.printStackTrace();
  } finally{
  rwl.readLock().unlock(); //读锁解锁
  }
  }
  public void put(Object data){
  rwl.writeLock().lock();  //写锁开启,这时只有一个写线程进入
  try {
  System.out.println(Thread.currentThread().getName()+"is ready to write");
  Thread.sleep(new Random().nextInt(100));
  this.data=data;
  System.out.println(Thread.currentThread().getName()+"have write date"+data);
  } catch (InterruptedException e) {
  e.printStackTrace();
  } finally{
  rwl.writeLock().unlock(); //写锁解锁
  }
  }
  }

6.现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

主要问join方法

Thread t1 = new Thread(new T1());
Thread t2 = new Thread(new T2());
Thread t3 = new Thread(new T3());

t1.start();
t1.join();

t2.start();
t2.join();

t3.start();
t3.join();

7.Thread类中的join()方法原理

join()方法的作用,t.join()方法阻塞调用此方法的线程,直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程

状态转换图

源码了解一下join()

public final void join() throws InterruptedException {
    join(0);
}
public final synchronized void join(long millis) throws InterruptedException {
    long base = System.currentTimeMillis();  //获取当前时间
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {    //这个分支是无限期等待直到b线程结束
        while (isAlive()) {
            wait(0);//wait操作,那必然有synchronized与之对应
        }
    } else {    //这个分支是等待固定时间,如果b没结束,那么就不等待了。
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

成员方法加了synchronized说明是synchronized(this),this是谁啊?this就是threadA子线程对象本身。也就是说,主线程持有了threadA这个对象的锁。
当子线程threadA执行完毕的时候,jvm会自动唤醒阻塞在threadA对象上的线程,在我们的例子中也就是主线程。至此,threadA线程对象被notifyall了,那么主线程也就能继续跑下去了。
总结
首先join() 是一个synchronized方法, 里面调用了wait(),这个过程的目的是让持有这个同步锁的线程进入等待,那么谁持有了这个同步锁呢?答案是主线程,因为主线程调用了threadA.join()方法,相当于在threadA.join()代码这块写了一个同步代码块,谁去执行了这段代码呢,是主线程,所以主线程被wait()了。然后在子线程threadA执行完毕之后,JVM会调用lock.notify_all(thread);唤醒持有threadA这个对象锁的线程,也就是主线程,会继续执行。

参考资料
https://www.techbelife.com/post/Implement-producer-consumer-model-with-wait-and-notifyAll.html
https://blog.csdn.net/u010983881/article/details/80257703

相关文章

  • 挂面09

    1.使用list队列/wait()/notify()实现生产者消费者 其中一种是通过阻塞队列(BlockingQu...

  • 超市买挂面,一定要看清一个字!吃了这么多年,居然今天才明白!

    鸡蛋挂面、杂粮挂面、营养素强化挂面…… 超市中的挂面品种还真不少 工作忙或是偶尔想偷懒的你 可能家里也会储备点挂面...

  • 挂面

    挂面是以小麦粉添加盐、碱、水经悬挂干燥后切制成一定长度的干面条。挂面始于元代,到建国前大部分都是手工制作,靠太阳晒...

  • 挂面

    材料: 挂面、酱油、老干妈、郫县豆瓣、香油,如果有点牛肉干甚佳。 烹调方法: 酱油铺满碗底,老干妈一小匙,一小筷(...

  • 挂面

    看着餐桌上冒着热气的挂面 一撮葱花, 半匙辣椒, 如你习惯的调料 如你喜欢的味道 我一条一条的吮吸 聊表挂念

  • 挂面

    和往常一般,煮了碗挂面 安在了你的位置 冒着热气 一撮葱花,半匙辣椒 如你习惯的调料, 如你喜欢的味道 聊表挂念,...

  • 挂面

    我应该是三年级开始独居的,爸妈姐姐们都在外,或赚钱去或上学去,总是一个偌大的院子,只有我一个人,不论白天黑夜,只有...

  • 挂面

    挂面早打唐代就开始有了。当时被叫做“须面”,被装入礼盒,馈赠亲朋,也有人家用作儿女婚嫁的聘礼。北方的饮食中,面类不...

  • 挂面!

    接上文 我就猜到那个朋友打王者去了,所以没看到我的消息,三十几分钟之后,我借到了锅哈哈哈! 借热水,插插头,煮面,...

  • 挂面

    今天收到了在网上买的挂面,挂面像银丝般细细的。 挂面本身就有盐味,我用清水煮了一碗,下了一些青菜和香菜,没有放油,...

网友评论

      本文标题:挂面09

      本文链接:https://www.haomeiwen.com/subject/symfpctx.html