1. 三组常见的线程协作api
2. 分析与简单使用
2.1 suspend()/resume()
:Thread类中的api,使用时易产生问题,已被弃用
问题分析:
- 由于suspend()方法不会释放对象锁,当在同步代码块中使用这组api,将会出现死锁
public static Object o = null;
private void q1() throws InterruptedException {
Thread consumerThread = new Thread(() -> {
while (true) {
if (o == null) {
System.out.println(Thread.currentThread().getName() + "进入等待");
synchronized (this){
Thread.currentThread().suspend(); //不会释放对象锁
}
}else {
System.out.println(Thread.currentThread().getName() + "等待结束");
break;
}
}
});
consumerThread.start();
Thread.sleep(1000L);
o = new Object();
synchronized (this) {
consumerThread.resume(); //死锁
}
System.out.println(consumerThread.getState());
System.out.println("主线程结束");
}
- 若在resume()前调用suspend(),线程将进入无限等待
public static Object o = null;
private void q2() throws InterruptedException {
Thread consumerThread = new Thread(() -> {
while (true) {
if (o == null) {
System.out.println(Thread.currentThread().getName() + "进入等待");
try {
// 让resume()先执行
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.currentThread().suspend(); //当前线程将进入无线等待
}else {
System.out.println(Thread.currentThread().getName() + "等待结束");
break;
}
}
});
consumerThread.start();
Thread.sleep(1000L);
o = new Object();
consumerThread.resume();
}
2.2 wait()/notify()/notifyAll()
:Object类中的api,推荐使用
public static Object o = null;
public void waitNotifyTest() throws Exception {
new Thread(() -> {
while (true) { //推荐在循环中使用
if (o == null) {
synchronized (this) {
try {
System.out.println(Thread.currentThread().getName() + "进入等待");
this.wait(); //释放对象锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(Thread.currentThread().getName() + "被唤醒,结束等待");
break;
}
}).start();
Thread.sleep(1000L);
o = new Object();
synchronized (this) {
this.notifyAll(); //唤醒持有该对象锁的其他线程
System.out.println(Thread.currentThread().getName() + "唤醒等待线程");
}
}
// 执行结果:
// Thread-0进入等待
// main唤醒等待线程
// Thread-0被唤醒,结束等待
public static Object o = null;
public void waitNotifyTest() throws Exception {
new Thread(() -> {
while (true) {
try {
if (o == null) {
Thread.sleep(2000L);
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "进入等待");
this.wait(); //无限等待
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "被唤醒,结束等待");
break;
}
}).start();
Thread.sleep(1000L);
o = new Object();
synchronized (this) {
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "唤醒等待线程");
}
}
// 执行结果:线程未终止
// main唤醒等待线程
// Thread-0进入等待
2.3 park()/unpark()
:JUC包下LockSupport的一组api
public static Object o = null;
public void parkUnparkTest() throws Exception {
Thread consumerThread = new Thread(() -> {
if (o == null) {
System.out.println(Thread.currentThread().getName() + "进入等待");
java.util.concurrent.locks.LockSupport.park();
}
System.out.println(Thread.currentThread().getName() + "被放行,结束等待");
});
consumerThread.start();
Thread.sleep(1000L);
o = new Object();
java.util.concurrent.locks.LockSupport.unpark(consumerThread);
System.out.println(Thread.currentThread().getName() + "放行");
}
//执行结果:
//Thread-0进入等待
//main放行
//Thread-0被放行,结束等待
public static Object o = null;
public void parkUnparkTest() throws Exception {
Thread consumerThread = new Thread(() -> {
if (o == null) {
System.out.println(Thread.currentThread().getName() + "进入等待");
synchronized (this) {
java.util.concurrent.locks.LockSupport.park();//不释放锁
}
}
System.out.println(Thread.currentThread().getName() + "被放行,结束等待");
});
consumerThread.start();
Thread.sleep(1000L);
o = new Object();
synchronized (this) {
java.util.concurrent.locks.LockSupport.unpark(consumerThread);//死锁
}
System.out.println(Thread.currentThread().getName() + "放行");
}
3. 使用wait()/notify()/notifyAll()
实现生产者消费者模型
直接上代码,如下:
/**
* @author : lin
* @date : 2021/3/2-14:17
*/
public class PCModel {
public static void main(String[] args) {
Store store = new Store(0, 100);
Thread c = new Thread(new Consumer(store));
Thread p = new Thread(new Producer(store));
Thread c1 = new Thread(new Consumer(store));
Thread p1 = new Thread(new Producer(store));
c.start();
p.start();
c1.start();
p1.start();
}
}
/** 消费动作 */
class Consumer implements Runnable{
private Store store;
public Consumer(Store store) {
this.store = store;
}
@Override
public void run() {
synchronized (store) {
while (true) {
if (store.rest <= store.maxSize * 0.2) {
try {
System.out.println("仓库即将无货,可以生产...");
store.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
store.rest--;
System.out.println(Thread.currentThread().getName() + "消费一件商品,库存还剩" + store.rest);
store.notifyAll();
}
}
}
}
}
/** 生产动作 */
class Producer implements Runnable{
private Store store;
public Producer(Store store) {
this.store = store;
}
@Override
public void run() {
synchronized (store) {
while (true) {
if (store.maxSize <= store.rest) {
try {
System.out.println("仓库已满,停止生产...");
store.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
store.rest++;
System.out.println(Thread.currentThread().getName() + "生产一件商品,库存还剩" + store.rest);
store.notifyAll();
}
}
}
}
}
/** 仓库 */
class Store{
int rest; //当前余量
int maxSize; //仓库最大存储量
public Store(Integer rest, Integer maxSize) {
this.rest = rest;
this.maxSize = maxSize;
}
}