wait:会释放锁,那个对象执行wait就会释放那个对象的锁
notify:唤醒一个等待锁的线程,实现线程之间的通信
notifyAll:唤醒等待锁的所有线程
wait ,notify,notifyAll 都是锁级别的操作,而每个Object对象头都有一把锁。所以这些方法放在Object类中
wait原理
- 首先从入口集entry set 开始去获取锁
- 获得了锁
- 执行wait方法释放锁进入wait set
- 被唤醒时开始尝试获取锁(线程的状态从waiting变成blockd)
- 获得锁(抢到锁后变成runnable)
- 执行完毕释放锁
用wait、notify实现生产消费者模式
package com.study.thread.object_thread_method;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
/**
* 描述: 用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();
}
}
}
class EventStorage {
private int maxSize;
private LinkedList<Date> storage;
public EventStorage() {
maxSize = 10;
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();
}
}
sleep:释放cpu不释放锁
wait和sleep方法的异同?
相同 :
1. Wait和sleep方法都可以使线程阻塞,对应线程状态是Waiting或Time_Waiting。
2. wait和sleep方法都可以响应中断Thread.interrupt()。
不同:
1. wait方法的执行必须在同步方法中进行,而sleep则不需要。
2. 在同步方法里执行sleep方法时,不会释放monitor锁,但是wait方法会释放 monitor锁。
3. sleep方法短暂休眠之后会主动退出阻塞,而没有指定时间的 wait方法则需要被 其他线程中断后才能退出阻塞。
4. wait()和notify(),notifyAll()是Object类的方法,sleep()和yield()是Thread类的方法
join:因为新的线程加入。所以要等它执行完一块出发。
注意中断的线程是谁。join的状态是waiting
package com.study.thread;
public class JOINInterrupt {
public static void main(String[] args) {
Thread main = Thread.currentThread();
Thread thread1 = new Thread(new Runnable(){
@Override
public void run(){
try {
main.interrupt();
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread1.start();
System.out.println("等待子线程运行完毕");
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+"主线程被中断");
}
System.out.println("子线程还没有执行完");
}
}