生产者消费者问题,用Synchronized关键字解决方法如下:
两个线程操作同一个对象,一个进行+1操作,一个进行-1操作。
本代码仅用于练习操作,不要直接在生产环境执行。
public class JUCTest01 {
public static void main(String[] args) throws InterruptedException {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
//判断是否等待,业务,干完活通知
class Data {
private int number = 0;
public synchronized void increment() throws InterruptedException {
if (number != 0) {
//等待
this.wait();
}
number++;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName() + "执行了+1" + ";number=" + number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
if (number == 0) {
//等待
this.wait();
}
number--;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName() + "执行了-1" + ";number=" + number);
this.notifyAll();
}
}
代码执行结果:
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
A执行了+1;number=1
B执行了-1;number=0
上面样例,仅存在AB两个对变量进行操作,如果我们将代码修改下,增加一CD等线程一起进行操作。
则会打印出number=2,3,负数等其他异常情况。
上述代码中我们用了if去进行判断其实是有问题的。
jdk文档中也注明,因为存在虚假唤醒,wait方法最好放在while循环中。
我们将上述方法if改为while条件判断下。
public class JUCTest01 {
public static void main(String[] args) throws InterruptedException {
Data data = new Data();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
//判断是否等待,业务,干完活通知
class Data {
private int number = 0;
public synchronized void increment() throws InterruptedException {
while (number != 0) {
//等待
this.wait();
}
number++;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName() + "执行了+1" + ";number=" + number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (number == 0) {
//等待
this.wait();
}
number--;
//通知其他线程,我+1完毕了
System.out.println(Thread.currentThread().getName() + "执行了-1" + ";number=" + number);
this.notifyAll();
}
}
再次执行打印结果,则可以正常输出01。