wait()方法
1. 方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法是用来将当前线程置
入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。
2. wait()方法只能在同步方法中或同步块中调用。如果调用wait()时,没有持有适当的锁,会抛出异常
3. wait()方法执行后,当前线程释放锁,其它线程可以竞争锁。
范例:wait()的使用方法
class MyThread implements Runnable{
private Object obj=new Object();
public void run(){
synchronized (obj){
System.out.println("wait start.....");
try {
//如果不中断线程,线程就会一直死等
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait end....");
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
MyThread myThread=new MyThread();
Thread thread=new Thread(myThread,"A");
thread.start();
Thread.sleep(3000);//休眠三秒钟
//在线程等待时中断该线程
thread.interrupt();
}
}
范例:wait(long timeout)的使用方法
class MyThread implements Runnable{
private Object obj=new Object();
public void run(){
synchronized (obj){
System.out.println("wait start.....");
try {
//如果一秒钟之内线程还没有被唤醒,一秒后线程继续执行
obj.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait end....");
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
MyThread myThread=new MyThread();
Thread thread=new Thread(myThread,"A");
thread.start();
}
}
notify()方法
notify方法就是使停止的线程继续运行。
- 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程。
- 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
范例:notify()随机唤醒一个线程
class MyThread implements Runnable{
private Object obj;
private boolean flag;
public MyThread(Object obj, boolean flag) {
this.obj = obj;
this.flag = flag;
}
public void waitMethod() {
synchronized (obj) {
System.out.println("wait start..."+Thread.currentThread().getName());
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait end...."+Thread.currentThread().getName());
}
}
public void notifyMethod() {
synchronized (obj) {
System.out.println("notify start..." + Thread.currentThread().getName());
obj.notify();
System.out.println("notify end...." + Thread.currentThread().getName());
}
}
@Override
public void run() {
if(flag){
waitMethod();
}else{
notifyMethod();
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
Object obj=new Object();
MyThread myThread=new MyThread(obj,true);
MyThread myThread1=new MyThread(obj,false);
for(int i=0;i<5;i++) {
Thread thread1 = new Thread(myThread, "等待线程"+i);
thread1.start();
}
Thread thread2=new Thread(myThread1,"唤醒线程");
Thread.sleep(1000);
thread2.start();
}
}
运行结果:只有随机的一个线程被唤醒,其他线程死等
如果想唤醒所有死等的线程,可以使用notifyAll(),用法与notify()一致。
注意:wait,notify必须使用在synchronized同步方法或者代码块内
线程阻塞
1. 线程调用 sleep()方法,主动放弃占用的处理器资源,但是不会释放对象锁。
2. 线程调用了阻塞式IO方法(read(),write()),在该方法返回前,线程被阻塞。
3. 线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。
4. 线程等待某个通知,即调用wait(),释放对象锁。
5. 程序调用了 suspend方法将该线程挂起。此方法容易导致死锁,尽量避免使用该方法。
run()方法运行结束后进入销毁阶段,整个线程执行完毕。
monitor的两个队列
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列。就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程。一个线程被唤醒后,才会进入就绪队列,等待CPU的调度;反之,一个线程被wait后,就会进入阻塞队列,等待下一次被唤醒。
生产者与消费者模型
范例:实现多个生产者与消费者进程模型
package hhh.pre.java;
import java.util.ArrayList;
import java.util.List;
//商品类
class Goods{
private String goodName;//商品名字
private int count;//商品数量
//生产了一个商品
public synchronized void set(String goodName){
while(count>0){
System.out.println("商品还有很多,可以打个盹休息一下~~~");
try {
//等待消费者消费
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.goodName=goodName;
this.count++;
System.out.println(toString()+Thread.currentThread().getName());
//唤醒等待消费的线程
notifyAll();
}
public synchronized void get(){
while(this.count==0){
System.out.println("商品买完啦,稍等一下,我们正在拼命生产~~~");
try {
//等待生产者生产
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.count--;
System.out.println(toString()+Thread.currentThread().getName());
//唤醒生产者继续生产商品
notifyAll();
}
@Override
public String toString() {
return "Goods{" +
"goodName='" + goodName + '\'' +
", count=" + count +
'}';
}
}
//消费者线程
class Consumer implements Runnable{
private Goods goods=new Goods();
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true) {
goods.get();
}
}
}
//
class Producer implements Runnable{
private Goods goods=new Goods();
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true) {
goods.set("MAC");
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
Goods goods=new Goods();
//存储多个生产、消费者线程
List<Thread> list =new ArrayList<>();
for(int i=0;i<10;i++){
Thread thread=new Thread(new Consumer(goods),"消费者"+i);
list.add(thread);
}
for(int i=0;i<5;i++){
Thread thread=new Thread(new Producer(goods),"生产者"+i);
list.add(thread);
}
for(Thread thread:list){
thread.start();
}
}
}
运行结果: