返回 登录
0

Thread的wait方法理解

wait方法是Object对象的方法。线程与锁是分不开的,线程的同步、等待、唤醒都与对象锁是密不可分的。wait方法会将当前线程放入wait set,等待被唤醒,并放弃lock对象上的所有同步声明,当前线程会因为线程调度的原因处于休眠状态而不可用。只有通过以下四个方法可以主动唤醒:
1. notify
2. notifyAll
3. Thread.interrupt()
4. 等待时间过完。

当线程被唤醒后,线程就从wait set中移除了并且重新获得线程调度能力,同时像其它线程一样持有object的锁。

一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,
在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁);
如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池等待队列中)。
取到锁后,他就开始执行同步代码(被synchronized修饰的代码);
线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中等待的某个线程就可以拿到锁执行同步代码了。
这样就保证了同步代码在统一时刻只有一个线程在执行。

这里就需要补充一下对象锁和类锁的区别。
事实上,synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。

线程正常结束后,会使以这个线程对象运行的wait()等待,退出等待状态!而如果在运行wait()之前,线程已经结束了,则这个wait就没有程序唤醒了。
原码里的join()方法,实际上就是运行的 wait(). 需要运行join的线程运行join方法,实际上是在此线程上调用了需要加入的线程对象的wait()方法,加入的线程运行完后,自然从wait退出了。

 到此,就得出了我的结论:
1 线程对象的wait()方法运行后,可以不用其notify()方法退出,会在线程结束后,自动退出。
2 线程间的等待唤醒机制,最好不要用线程对象做同步锁!

首先我们看一个实例:

public class TestDemo {
    public static void main(String []args) throws InterruptedException{
        MyThread myThread = new MyThread();
        System.out.println("before");
        myThread.start();
        System.out.println("after");
    }

    static class MyThread extends Thread{

        public void run(){
            synchronized (this) {
                for(int i=0;i<3;i++){
                    System.out.println("number:"+ i);
                }
            }
        }
    }
}

输出的结果是:
before
after
number:0
number:1
number:2

首先是Main线程具有抢占cpu资源,然后执行完后,在开始执行子线程。

实例2:

public class TestDemo {
    public static void main(String []args) throws InterruptedException{
        MyThread myThread = new MyThread();
        System.out.println("before");
        myThread.start();
        synchronized (myThread) {
            myThread.wait();
        }
        System.out.println("after");
    }

    static class MyThread extends Thread{

        public void run(){
            synchronized (this) {
                for(int i=0;i<3;i++){
                    System.out.println("number:"+ i);
                }
            }
        }
    }
}

before
number:0
number:1
number:2
after

我们调用wait方法,Main线程会释放当前锁,进入wait set。然后子线程开始运行,当子线程运行完毕后,会把锁归还。

评论