3_线程间通信
Posted root_zhb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3_线程间通信相关的知识,希望对你有一定的参考价值。
场景:有多个线程,实现对一个初始值为0的变量进行操作,实现如下效果(不要求ABCD的顺序)
A 1 B 0 C 1 D 0
A 1 B 0 C 1 D 0
A 1 B 0 C 1 D 0
1、虚假唤醒问题
1.1、错误代码
//第一步:创建资源类,定义属性和操作方法
class Share{
//初始值
private int number=0;
// +1的方法
public synchronized void incr() throws InterruptedException {
//第二步:判断、干活、通知
if(number!=0){ //判断number的值是否是0,如果不是0,等待
this.wait();
}
//如果number值是0,就+1操作
number++;
System.out.println(Thread.currentThread().getName()+"::"+number);
//通知其他线程
this.notifyAll();
}
// -1的方法
public synchronized void decr() throws InterruptedException {
//判断
if(number!=1){ //判断number的值是否是1,如果不是1,等待
this.wait();
}
//干活
number--;
System.out.println(Thread.currentThread().getName()+"::"+number);
//通知其他线程
this.notifyAll();
}
}
public class ThreadTest {
public static void main(String[] args) {
Share share=new Share();
new Thread(()->{
for (int i=0;i<10;i++){
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"AA").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"BB").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
share.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"CC").start();
new Thread(()->{
for (int i=0;i<10;i++){
try {
share.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"DD").start();
}
}
1.2、现象
BB::4
DD::3
BB::2
CC::3
AA::4
CC::5
1.3、原因分析
简单来说,就是当某个线程第二次醒来之后,没有进行判断
1.4、解决
不管什么时候,让线程醒来之后,再次判断即可,也就是 wait()方法总是应该在循环中使用。
//将两个判断方法改成while循环
while(number!=0){
this.wait();
}
while(number!=1){
this.wait();
}
2、Synchronized 实现
将两个判断条件替换为while循环,即为synchronized实现。
3、Lock实现
//第一步:创建资源类,定义属性和操作方法
class Share{
//初始值
private int number=0;
//创建Lock
private Lock lock=new ReentrantLock ();
private Condition condition=lock.newCondition();
// +1的方法
public void incr() throws InterruptedException {
//上锁
lock.lock();
try {
//判断、干活、通知
while(number!=0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"::"+number);
condition.signalAll();
}finally {
//解锁
lock.unlock();
}
}
// -1的方法
public void decr() throws InterruptedException {
lock.lock();
try {
while(number!=1){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"::"+number);
condition.signalAll();
}finally {
lock.unlock();
}
}
}
以上是关于3_线程间通信的主要内容,如果未能解决你的问题,请参考以下文章