Java程序栈Java Web知识

五、线程之间的协作

2019-10-11  本文已影响0人  一直想上树的猪

一、典型例子:生产者消费者

自行百度,不作赘述

二、业务场景

当A线程对一个变量进行修改,然后通知其他线程之后,B线程根据这个通知进行触发相应的业务逻辑。
最笨的方法:我们首先会在B线程中:

while(条件不满足){
  check 条件不满足
  sleep(50);
}

但是这种做法有个问题,不能保证业务变化的及时性,即可能我刚开始休眠这个条件就已经满足了还需要等待固定的时间,有人就说:那我可以把休眠时间调整的尽可能小,那么对于我们的CPU的负载压力就很大了,因此这种方式是有弊端的。

wait()

当A线程的O对象调用wait()方法之后,进入等待状态,只有当B线程调用O对象的notify()或notifyAll()方法之后才会唤醒A线程。A唤醒之后做自己的相关业务工作。

notify()和notifyAll()

如果某些线程在等待某些条件触发,那当那些条件为真时,你可以用 notify 和 notifyAll 来通知那些等待中的线程重新开始运行。不同之处在于,notify 仅仅通知一个线程,并且我们不知道哪个线程会收到通知,然而 notifyAll 会通知所有等待中的线程。换言之,如果只有一个线程在等待一个信号灯,notify和notifyAll都会通知到这个线程。但如果多个线程在等待这个信号灯,那么notify只会通知到其中一个,而其它线程并不会收到任何通知,而notifyAll会唤醒所有等待中的线程。

三、等待和通知的标准范式

等待方要进行等待时:

syn(对象){
    while(条件不满足){
        对象.wait()
    }
    条件满足了,做业务逻辑
}

通知方:

syn(对象){
    改变条件
    对象.notify()/notifyAll()
}

四、notify()和notifyAll()应该用谁

notify()具有随机性,因为不知道要唤醒哪一个,所以在不确定要唤醒具体哪个线程的时候,最好是用notifyAll(),谨慎使用notify()。

五、市面上所有的连接池都是通过等待超时模式实现的

一个连接池中有固定的(比如10个)连接数,如果在某一时刻并发量上来了,有50个请求需要访问数据库,那么只会有十个请求去成功地访问到数据库中,剩下的40个线程会进入到一个等待状态,只有当十个已经连接数据库的线程的业务处理完毕,释放掉数据库的连接,才会去通知剩余的40个线程,然后从剩余的40个连接中挑一个线程去进行数据库的连接。

六、调用yield()、sleep()、wait()、notify()等方法对锁有何影响?

调用yield()、sleep()之后,当前线程所持有的锁是不会被释放的
调用wait()方法之后会释放当前线程锁持有的锁,被唤醒之后会重新竞争锁。
调用notify()后对锁没有任何影响,但是在调用notify()时,一定要放在一个同步块里面,线程只有在执行完整个同步块后,才会自然而然释放锁,因此notify()一般放在代码同步块的最后一行。

上一篇下一篇

猜你喜欢

热点阅读