Java并发编程系列文章
《一》多线程基础——Java线程与进程的基本概念
《二》多线程基础——Java线程入门类和接口
《三》多线程基础——Java线程组和线程优先级
《四》多线程基础——Java线程生命周期及转换
《五》多线程基础——Java线程间的通信(互斥与协作)
《六》实际应用——如何优雅的关闭线程
《七》实际应用——生产者与消费者模型
并发编程(多线程)
一直以来都是程序员头疼的难题。曾经听别人总结过并发编程的第一原则,那就是不要写并发程序,哈哈哈。后来发现,这样能够显著提高程序响应和吞吐量的利器,哪还能忍得住不会用呢?
整理出《Java并发编程系列文章》,共计7篇,与君共勉。
《七》实际应用——生产者与消费者模型
1、会阻塞的生产者消费者模型,思考为什么?
生产者和消费者模型,应用非常广泛。这是一个经典错误的例子,引以为戒。
public class No6_produce_consumer_test{
private int i = 0;
final private static Object lock = new Object();
private volatile boolean flag = false;
public void produce(){
synchronized (lock){
if(flag){
try {
System.out.println(Thread.currentThread().getName()+"-->waiting");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
i++;
System.out.println(Thread.currentThread().getName()+"-->" + i);
flag = true;
lock.notify(); //todo 通知来消费
}
}
}
public void consumer(){
synchronized (lock){
if(flag){
System.out.println(Thread.currentThread().getName()+"-->" + i);
flag = false;
lock.notify(); //todo 通知去生产
}else{
try {
System.out.println(Thread.currentThread().getName()+"-->waiting");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
No6_produce_consumer_test pc = new No6_produce_consumer_test();
Stream.of("P1","P2").forEach(n -> {
new Thread(n){
@Override
public void run() {
while (true){
pc.produce();
}
}
}.start();
});
Stream.of("C1","C2").forEach(n -> {
new Thread(n){
@Override
public void run() {
while (true){
pc.consumer();
}
}
}.start();
});
}
}
运行结果就是两个生产者和两个消费者都会阻塞,程序卡死。原因就是:lock.notify()会随机唤醒一个放弃lock锁的阻塞的线程,可能唤醒生产者,也可能唤醒消费者。当生产者唤醒生产者,或者消费者唤醒消费者时,就会出现这样的问题。
2、正确的生产者消费者模型
public class No6_produce_consumer_dev {
private int i = 0;
final private static Object lock = new Object();
private volatile boolean flag = false;
public void produce(){
synchronized (lock){
while (flag){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
i++;
System.out.println(Thread.currentThread().getName()+"-->" + i);
flag = true;
lock.notifyAll(); //todo 通知来消费
}
}
public void consumer(){
synchronized (lock){
while(flag){
System.out.println(Thread.currentThread().getName()+"-->" + i);
flag = false;
lock.notifyAll(); //todo 通知去生产
}
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
No6_produce_consumer_dev pc = new No6_produce_consumer_dev();
Stream.of("P1","P2","P3","P4").forEach(n -> {
new Thread(n){
@Override
public void run() {
while (true){
pc.produce();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
});
Stream.of("C1","C2","C3","C4").forEach(n -> {
new Thread(n){
@Override
public void run() {
while (true){
pc.consumer();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
});
}
}