说明:本系列内容部分转载于他人博客,部分自己总结和测试代码。如理解有问题,欢迎博友指正。
本篇主要介绍多线程中两个经典的问题:死锁、生产者和消费者模型
一、死锁
死锁是由于多线程间获取锁时冲突了。比如,有两个线程 A、B,有两个锁 1、2。线程 A 先获取了锁1,在锁1 的代码中需要获取锁 2执行完才释放锁 1,而此时线程 B 获取了锁 2;在锁2 的代码中需要获取锁 1执行完才释放锁 2。此时就发生了死锁
public class TestDeadLock implements Runnable{
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
public static void main(String[] argv){
TestDeadLock td1 = new TestDeadLock();
TestDeadLock td2 = new TestDeadLock();
td1.flag = 1;
td2.flag = 0;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start();
}
public void run(){
System.out.println("flag = "+ flag);
if(flag == 1){
synchronized (o1){
try{
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
synchronized(o2){
System.out.println("1");
}
}
}
if(flag == 0){
synchronized(o2){
try{
Thread.sleep(500);
}catch(Exception e){
e.printStackTrace();
}
synchronized(o1){
System.out.println("0");
}
}
}
}
}
解决方案:
- 让所有的线程按照同样的顺序获得一组锁。这种方法消除了 X 和 Y 的拥有者分别等待对方的资源的问题。
- 将多个锁组成一组并放到同一个锁下。前面Java线程死锁的例子中,可以创建一个总锁。于是在获得1或2之前都必须获得总锁。
二、生产者消费者模型
这个问题主要就是 wait、notify、notifyAll 的问题,直接上代码
仓库类
import java.util.LinkedList;
import java.util.List;
public class Storage {
private static int MAX_SIZE;
private List<Object> list = new LinkedList<>();
public Storage(int mAX_SIZE) {
super();
MAX_SIZE = mAX_SIZE;
}
public void consume(int num){
synchronized (list) {
while(num > list.size()){
System.out.println("现库存【" + list.size() + "】,消费【" + num + "】。暂时无法消费");
try {
list.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("现库存【" + list.size() + "】,消费【" + num + "】。开始消费");
for(int i=0; i<num; i++){
list.remove(0);
}
list.notifyAll();
}
}
public void produce(int num){
synchronized (list) {
while((list.size() + num) > MAX_SIZE){
System.out.println("现库存空余【" + (MAX_SIZE - list.size()) + "】,生产【" + num + "】。暂时无法生产");
try {
list.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("现库存空余【" + (MAX_SIZE - list.size()) + "】,生产【" + num + "】。开始生产");
for(int i=0; i<num; i++){
list.add(new Object());
}
list.notifyAll();
}
}
}
生产者类
public class Producer implements Runnable{
private int num;
private Storage storage;
public Producer(Storage storage, int num) {
super();
this.num = num;
this.storage = storage;
}
public void produce(){
storage.produce(num);
}
@Override
public void run() {
// TODO Auto-generated method stub
produce();
}
}
消费者类
public class Consumer implements Runnable{
private int num;
private Storage storage;
public Consumer(Storage storage, int num) {
super();
this.num = num;
this.storage = storage;
}
public void consume(){
storage.consume(num);
}
@Override
public void run() {
// TODO Auto-generated method stub
consume();
}
}
测试类
public class Test {
public static void main(String[] args) {
Storage storage = new Storage(100);
Producer p1 = new Producer(storage, 10);
Producer p2 = new Producer(storage, 10);
Producer p3 = new Producer(storage, 10);
Producer p4 = new Producer(storage, 10);
Producer p5 = new Producer(storage, 10);
Producer p6 = new Producer(storage, 10);
Producer p7 = new Producer(storage, 80);
// 消费者对象
Consumer c1 = new Consumer(storage, 50);
Consumer c2 = new Consumer(storage, 20);
Consumer c3 = new Consumer(storage, 30);
// 线程开始执行
new Thread(c1).start();
new Thread(c2).start();
new Thread(c3).start();
new Thread(p1).start();
new Thread(p2).start();
new Thread(p3).start();
new Thread(p4).start();
new Thread(p5).start();
new Thread(p6).start();
new Thread(p7).start();
}
}
执行结果:
现库存【0】,消费【50】。暂时无法消费
现库存【0】,消费【30】。暂时无法消费
现库存空余【100】,生产【10】。开始生产
现库存空余【90】,生产【10】。开始生产
现库存空余【80】,生产【10】。开始生产
现库存【30】,消费【20】。开始消费
现库存【10】,消费【30】。暂时无法消费
现库存【10】,消费【50】。暂时无法消费
现库存空余【90】,生产【10】。开始生产
现库存空余【80】,生产【10】。开始生产
现库存空余【70】,生产【10】。开始生产
现库存空余【60】,生产【80】。暂时无法生产
现库存【40】,消费【50】。暂时无法消费
现库存【40】,消费【30】。开始消费
现库存【10】,消费【50】。暂时无法消费
现库存空余【90】,生产【80】。开始生产
现库存【90】,消费【50】。开始消费