文章目录
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f3e66dae576182255686baa1fb4570c9.png)
wait, notify, notifyAll 方法详解
是Object
类的方法。因此是对象的方法。
阻塞阶段:获取了对象的modify锁,进入休眠
唤醒方法:
- 另一个线程调用这个对象的
notify()
方法且刚好唤醒的是本线程; - 另一个线程调用这个对象的
notifyAll()
方法; - 过了
wait()
等待的时间; - 等待的过程中调用
interrupt()
也会被唤醒;
遇到中断:抛出异常,释放锁。
特点性质:用必须先拥有monitor、只能唤醒一个、属于Object类、考虑同时持有多个锁的情况
手写生产者消费者设计模式
需要实现一个public类,三个单独的类,分别实现仓库(构造器:构造仓库,方法:get,take),消费者模式(构造器,继承Runnable重写run,调用take方法),生产者模式(构造器,继承Runnable,调用put方法)
package threadObjectClassCommonMethods;
import java.util.Date;
import java.util.LinkedList;
/**
* @Author: chenzuoZhang
* @package: threadObjectClassCommonMethods
* @time: 2020/8/17
* @TODO: 用wait/notify实现生产者消费者模式
*/
public class ProducerConsumerModel {
public static void main(String[] args) {
EventStorage eventStorage = new EventStorage();
Producer producer = new Producer(eventStorage);
Consumer consumer = new Consumer(eventStorage);
new Thread(producer).start();
new Thread(consumer).start();
}
}
// 实现生产者模式
class Producer implements Runnable{
private EventStorage storage;
// 构造器,得到仓库
public Producer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
// 实现消费者模式
class Consumer implements Runnable{
private EventStorage storage;
// 构造器,得到仓库
public Consumer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
// 建立仓库类,实现get和take方法
class EventStorage{
private int maxSize;
private LinkedList<Date> storage;
public EventStorage(){
maxSize = 10;
this.storage = new LinkedList<>();
}
public synchronized void put(){
while (storage.size() == maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date()); // 每次往仓库里加入一个日期
System.out.println("仓库里有 " + storage.size()+" 件物品");
notify();
}
public synchronized void take(){
while (storage.size() == 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("拿到了 "+storage.poll()+"物品,现在容量为"+storage.size());
notify();
}
}
奇偶线程打印
package threadObjectClassCommonMethods;
/**
* @Author: chenzuoZhang
* @TODO: 采用wait和notify提高效率 方法:拿到锁就打印,然后唤醒其他的,自己休眠
*/
public class OddAndEven2 {
private static final Object lock = new Object();
private static int count = 0;
public static void main(String[] args) {
new Thread(new TurningRunner(),"0").start();
new Thread(new TurningRunner(),"1").start();
}
static class TurningRunner implements Runnable{
@Override
public void run() {
while (count<100){
synchronized (lock){
System.out.println(Thread.currentThread().getName()+count++);
// 注意,这里一定是lock.notifyAll(); 而不是notifyAll()
lock.notifyAll();
if (count<100) {
try {
// 注意,这里一定是lock.wait(); 而不是wait() 否则会休眠主线程?
lock.wait();
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
为什么这几个方法在Object方法里,而sleep在Thread里
因为这几个操作是锁的操作,都是绑定于对象的,所有的对象都是可以作为所队形。sleep
是Thread
级别的。
Thread
类不适合作为锁。
sleep方法详解
sleep
让线程进入waiting
状态,并且不占用CPU资源。sleep
方法在时间未到时候不会释放锁的,但是wait
是释放锁的。sleep方法是可以响应中断的,抛出中断并清除中断状态。
wait/notify、sleep的异同
相同:都是可以让线程进入阻塞状态;可以相应中断
不同:wait/notify
是Object类;需要在同步方法中进行执行,sleep不需要;释放锁的区别;sleep必须传参。
- sleep() 和 wait() 有什么区别?
- sleep() 是 Thread 类的静态本地方法;wait() 是Object类的成员本地方法
- sleep() 方法可以在任何地方使用;wait() 方法则只能在同步方法或同步代码块中使用,否则抛出异常Exception in thread “Thread-0” java.lang.IllegalMonitorStateException
- sleep() 会休眠当前线程指定时间,释放 CPU 资源,不释放对象锁,休眠时间到自动苏醒继续执行;wait() 方法放弃持有的对象锁,进入等待队列,当该对象被调用 notify() / notifyAll() 方法后才有机会竞争获取对象锁,进入运行状态
- JDK1.8 sleep() wait() 均需要捕获 InterruptedException 异常
join方法
作用:因为新的线程加入了我们,所以我们要等他执行完再出发;
用法:main等待thread执行完毕。
当等待其他线程join期间,主线程处于waiting状态。
本质上还是调用了wait()
,最后Thread方法实现notify。
yield方法
作用:释放CPU时间片,线程状态依然是Runnable。不释放锁。
与sleep的区别,sleep方法不是随时可以被调度的,yield可以被随时调度。
获取当前线程引用,Thread.currentThread()方法
Start和run方法
stop,suspend,resume方法
被弃用