wait()方法

wait() 方法就是让线程停止运行
wait():运行态-->阻塞态
注意:

  • 方法wait()的作用是使当前执行代码的线程进行等待,将当前线程置入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止
  • wait()方法只能在同步方法中或同步块中调用(synchronized中)。如果调用wait()时,没有持有适当的锁,会抛出异常
  • wait()方法执行后,当前线程释放锁

观察wait()方法的使用

public class testWait {
    public static void main(String[] args) {
        Object ob = new Object();
        synchronized (ob){
            System.out.println("等待中...");
            try {
                ob.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("等待已过时...");
        }
        System.out.println("main方法结束..");
    }
}

这样在执行到object.wait()之后就一直等待下去,那么程序肯定不能一直这么等待下去了。这个时候就需要使用到了另外一个方法唤醒的方法notify()。

notify()方法

notify()方法就是让停止的线程继续运行
notify();阻塞态-->就绪态
调用notify后,将等待队列中的线程唤醒置入同步队列末尾排队获取锁
注意:

  • notify()方法也要在同步方法或同步块中调用(synchronized中),该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程
  • 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁

使用notify()方法唤醒线程

class MyThread implements Runnable{
    private boolean flag;
    private Object obejct;

    public MyThread(boolean flag,Object object) {
        super();
        this.flag = flag;
        this.obejct=object;
    }
    public void waitMethod(){
        synchronized (obejct){
            try {
                while(true) {
                    System.out.println("wait()方法开始.." + Thread.currentThread().getName());
                    obejct.wait();
                    System.out.println("wait方法()结束.." + Thread.currentThread().getName());return;
                }
            } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public void notifyMethod(){
        synchronized (obejct) {
            try {
                System.out.println("notify()方法开始..." + Thread.currentThread().getName());
                obejct.notify();
                System.out.println("notify()方法结束..." + Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        if(flag){
            this.waitMethod();
        }else{
            this.notifyMethod();
        }
    }
}
public class testnotify {
    public static void main(String[] args)throws InterruptedException {
        Object object = new Object();
        MyThread waitThread = new MyThread(true,object);
        MyThread notifyThread = new MyThread(false,object);
        Thread thread1 = new Thread(waitThread,"wait线程");
        Thread thread2 = new Thread(notifyThread,"notify线程");
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
        System.out.println("main方法结束!!");
    }
}

运行结果:

wait()方法开始..wait线程
main方法结束!!
notify()方法开始...notify线程
notify()方法结束...notify线程
wait方法()结束..wait线程

从结果上来看第一个线程执行的是一个waitMethod方法,该方法里面有个死循环并且使用了wait方法进入等待状态将释放锁,如果这个线程不被唤醒的话将会一直等待下去,这个时候第二个线程执行的是notifyMethod方法,该方法里面执行了一个唤醒线程的操作,并且一直将notify的同步代码块执行完毕之后才会释放锁然后继续执行wait结束打印语句

notifyAll()方法

notifyAll()方法唤醒所有等待线程
使用notifyAll()方法唤醒所有等待线程
只有一个等待队列时,唤醒所有线程一定会造成不该唤醒线程的线程又被唤醒然后再次阻塞,造成性能开销

class MyThread implements Runnable{
    private boolean flag;
    private Object obejct;

    public MyThread(boolean flag,Object object) {
        super();
        this.flag = flag;
        this.obejct=object;
    }
    public void waitMethod(){
        synchronized (obejct){
            try {
                while(true) {
                    System.out.println("wait()方法开始.." + Thread.currentThread().getName());
                    obejct.wait();
                    System.out.println("wait方法()结束.." + Thread.currentThread().getName());return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void notifyMethod(){
        synchronized (obejct) {
            try {
                System.out.println("notifyAll()方法开始..." + Thread.currentThread().getName());
                obejct.notifyAll();
                System.out.println("notifyAll()方法结束..." + Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        if(flag){
            this.waitMethod();
        }else{
            this.notifyMethod();
        }
    }
}
public class testnotifyAll {
    public static void main(String[] args)throws InterruptedException {
        Object object = new Object();
        MyThread waitThread1 = new MyThread(true,object);
        MyThread waitThread2 = new MyThread(true,object);
        MyThread waitThread3 = new MyThread(true,object);
        MyThread notifyThread = new MyThread(false,object);
        Thread thread1 = new Thread(waitThread1,"wait1线程");
        Thread thread2 = new Thread(waitThread1,"wait2线程");
        Thread thread3 = new Thread(waitThread1,"wait3线程");
        Thread thread4 = new Thread(notifyThread,"notify线程");
        thread1.start();
        thread2.start();
        thread3.start();
        Thread.sleep(1000);
        thread4.start();
        System.out.println("main方法结束!!");
    }
}

运行结果:
在main方法结束后由1s的等待,然后notifyAll()方法就唤醒了所有等待线程,继续运行

wait()方法开始..wait1线程
wait()方法开始..wait3线程
wait()方法开始..wait2线程
main方法结束!!
notifyAll()方法开始...notify线程
notifyAll()方法结束...notify线程
wait方法()结束..wait1线程
wait方法()结束..wait2线程
wait方法()结束..wait3线程

Process finished with exit code 0

注意:唤醒线程不能过早,如果在还没有线程在等待中时,过早的唤醒线程,这个时候就会出现先唤醒,在等待的效果了。这样就没有必要在去运行wait方法了。

出现阻塞的情况大体分以下五种:

  • 线程调用 sleep方法,主动放弃占用的处理器资源
  • 线程调用了阻塞式IO方法,在该方法返回前,该线程被阻塞
  • 线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有
  • 线程等待某个通知
  • 程序调用了 suspend方法将该线程挂起。此方法容易导致死锁,尽量避免使用该方法
run()方法运行结束后进入销毁阶段,整个线程执行完毕
Object及其子类的每个对象都有两个队列

同步队列:获取该对象锁失败的线程进入同步队列
等待队列:调用wait()的线程进入等待(等待被notify)
在这里说一下什么是守护线程和用户线程

守护线程:

java中线程只有两类:用户线程,守护线程
创建的线程默认都是用户线程,包括主线程
守护线程:后台线程,只有当当前JVM进程中最后一个用户线程终止,守护线程会随着JVM一同停止
GC线程是一个典型的守护线程
**setDeamn**将当前用户线程置为守护线程