LockSupport的park() / unpark()方法与wait() / notify()方法的区别

LockSupport类是JDK种rt.jar包中的工具类,它主要的作用是挂起和唤醒,该工具类是创建锁和其他同步类的基础。

 

LockSupport类采用的是许可证机制,该类与使用它的线程都会关联一个许可证,在默认情况下调用LockSupport类方法的线程是不存在许可证的。LockSupport是使用UnSafe类实现的。

LockSupport的park()方法与unpart(Thread thread)方法

park():线程调用LockSupport.park()方法,首先需要判断该线程是否持有许可证,如果没有持有,则该线程阻塞挂起,直至获得许可证;如果该线程已持有许可证,线程会继续执行。

unpark(Thread thread):线程调用LockSupport.unpark()方法,给该线程发放许可证,如果线程调用park()方法阻塞挂起,则唤醒该线程继续执行,如果在该方法之后调用park()方法,线程会继续执行,不会被阻塞。

示例代码如下

/**
 * 调用LockSupport.park()的线程类
 */
public class PartThread extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("线程"+Thread.currentThread().getId()+"begin park");
        LockSupport.park();
        System.out.println("线程"+Thread.currentThread().getId()+"end park");
    }
}
/**
 * 调用LockSupport.unpark(Thread thred)方法的线程类
 */
public class UnpartThread extends Thread{
    private PartThread partThread;

    public UnpartThread(PartThread partThread) {
        this.partThread=partThread;
    }

    @Override
    public void run() {
        System.out.println("线程"+Thread.currentThread().getId()+"-执行unpart前-----------");
        LockSupport.unpark(partThread);
        System.out.println("线程"+Thread.currentThread().getId()+"-执行unpart后-----------");
    }
}

测试代码:

public class Demo {
    public static void main(String[] args) {
        PartThread partThread = new PartThread();
        UnpartThread unpartThread=new UnpartThread(partThread);
        partThread.start();
        unpartThread.start();
    }
}

测试结果:

从结果上看,线程是先调用unpark()方法,而后再调用park()方法。所以线程调用park()前已存在许可证,从而调用park()之后没有进入阻塞状态,继续执行。

那如果先调用notify()方法,在调用wait()方法会产生什么样的结果呢?会和使用park()方法和unpark方法一样吗?可先思考一下该问题,在继续往下看。

 

wait()与notify()方法

wait():线程调用wait()后,线程进入阻塞状态,直至该线程调用notify()方法或notifyAll(),该线程从阻塞状态进入可运行状态。

notify():唤醒等待中的线程

示例代码如下:

/**
 * 调用wait()方法的线程类
 */
public class WaitThrad extends Thread {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println("线程"+Thread.currentThread().getId()+"begin wait");
            synchronized (this){
                wait();
            }
            System.out.println("线程"+Thread.currentThread().getId()+"end wait");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
/**
 * 调用notify()方法的线程类
 */
public class NotifyThread extends Thread{
    private WaitThrad waitThrad;

    public NotifyThread(WaitThrad waitThrad) {
        this.waitThrad = waitThrad;
    }

    @Override
    public void run() {
        System.out.println("线程"+Thread.currentThread().getId()+"-执行notify前-----------");
        synchronized (waitThrad){
            waitThrad.notify();
        }
        System.out.println("线程"+Thread.currentThread().getId()+"-执行notify后-----------");
    }
}

测试代码:

public class Demo {
    public static void main(String[] args) {
        WaitThrad waitThrad = new WaitThrad();
        NotifyThread notifyThread=new NotifyThread(waitThrad);
        waitThrad.start();
        notifyThread.start();
    }
}

测试结果:

由结果可看出,notify()方法是在线程调用wait()方法前执行的。这个时候线程调用wait()方法,wait()方法线程一直处于阻塞等待状态。

所以,在调用wait()方法之前调用notify()方法,wait()方法会错失信号,进入无限等待状态,从而产生死锁。

还有一点区别,就是wait()方法和notify()方法需要与sychronized锁机制一起使用,否则会产生java.lang.IllegalMonitorStateException异常,这个有兴趣的话可以去除sychronized锁机制,自己尝试一下

 

总结:

park()与unpark()方法:只要线程存在许可证,不管是在park()方法前或者调用park()方法后拥有,线程都会继续执行。

wait()与notify()方法:wait()方法必须要在notify()方法之前执行,否则wait()方法错失信号,进入无限等待状态,从而产生死锁

 

 

 

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页