六、LockSupport

1、为什么使用LockSupport类

如果只是LockSupport在使用起来比Object的wait/notify简单,

那还真没必要专门讲解下LockSupport。最主要的是灵活性。
①LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。

②unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。

上边的例子代码中,主线程调用了Thread.sleep(1000)方法来等待线程A计算完成进入wait状态。如果去掉Thread.sleep()调用,代码如下:

note:这个场景需要注意一下 防止在业务场景中出现这种bug。

public class TestObjWait {

    public static void main(String[] args)throws Exception {
        final Object obj = new Object();
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                int sum = 0;
                for(int i=0;i<10;i++){
                    sum+=i;
                }
                try {
                    synchronized (obj){
                        obj.wait();
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println(sum);
            }
        });
        A.start();
        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法
        //Thread.sleep(1000);
        synchronized (obj){
            obj.notify();
        }
    }
}

多运行几次上边的代码,有的时候能够正常打印结果并退出程序,但有的时候线程无法打印结果阻塞住了。原因就在于:主线程调用完notify后,线程A才进入wait方法,

导致线程A一直阻塞住。由于线程A不是后台线程,所以整个程序无法退出。
那如果换做LockSupport呢?LockSupport就支持主线程先调用unpark后,线程A再调用park而不被阻塞吗?是的,没错。代码如下:

public class TestObjWait {

    public static void main(String[] args)throws Exception {
        final Object obj = new Object();
        Thread A = new Thread(new Runnable() {
            @Override
            public void run() {
                int sum = 0;
                for(int i=0;i<10;i++){
                    sum+=i;
                }
                LockSupport.park();
                System.out.println(sum);
            }
        });
        A.start();
        //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法
        //Thread.sleep(1000);
        LockSupport.unpark(A);
    }
}

不管你执行多少次,这段代码都能正常打印结果并退出。这就是LockSupport最大的灵活所在。

总结一下,LockSupport比Object的wait/notify有两大优势:

①LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。

②unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。

1.LockSupport的等待和唤醒例子

package day03.part2;

import java.util.concurrent.locks.LockSupport;

/**
 *LockSupport的等待和唤醒
 * @author xzq
 */
public class LockSupportTest01 {


    public static void main(String[] args) {

        Thread t= new Thread("子线程"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+":开始执行……");
                System.out.println(threadName+":睡眠中……");
                LockSupport.park();//等待
                System.out.println(threadName+":执行结束!");
            }

        };
        t.start();
        try{
            Thread.sleep(1000);
        }catch(Exception e){

        }
        System.out.println("main:已唤醒子线程1次");
        LockSupport.unpark(t);//唤醒 可以唤醒指定线程 t
        System.out.println("main:执行结束……");

    }

}

package day03.part2;

/**
 *LockSupport的等待和唤醒
 *先唤醒,再等待的情况
 *相当于对唤醒进行了一个抵消作用,
 *本人称之为:0  -1  0作用
 * @author xzq
 */
public class LockSupportTest02 {


    public static void main(String[] args) {

        Thread t= new Thread("子线程"){
            @Override
            public synchronized void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+":开始执行……");
                System.out.println(threadName+":唤醒前---------");
                this.notify();
//              LockSupport.unpark(this);
                System.out.println(threadName+":唤醒后---------");

                System.out.println(threadName+":等待前---------");
                try {
                    this.wait();
                } catch (InterruptedException e) {
                }
//              LockSupport.park();
                System.out.println(threadName+":等待后---------");

                System.out.println(threadName+":执行结束!");
            }
        };
        t.start();
        System.out.println("main:执行结束……");
    }

}

2.LockSupport的等待是否释放锁

package day03.part2;

/**
 *LockSupport的等待是否释放锁
 * @author xzq
 */
public class LockSupportTest03 {

    private synchronized static void testSync() throws InterruptedException{
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":进入同步方法……");
        System.out.println(threadName+":开始等待……");
        for(int i=1;i<=3;i++){
            //sleep不释放锁
            System.out.println(threadName+":现在是在同步方法中的等待的第"+i+"秒");
            Thread.sleep(1_000);

            /*//wait要释放锁
            LockSupportTest03.class.wait(1_000);
            System.out.println(threadName+":现在是在同步方法中的第"+i+"秒");*/

            /*//LockSupport的park方法不释放锁
            //注意这个参数是纳秒:1秒等于1千毫秒,等于100万微秒,等于10亿纳秒
            LockSupport.parkNanos(1_000_000_000);
            LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));*/

            System.out.println(threadName+":现在是在同步方法中的第"+i+"秒");
        }
        System.out.println(threadName+":离开同步方法……");
    }


    public static void main(String[] args) {
        //开启两个线程去执行同步方法
        for(int i=1;i<=2;i++){
            new Thread("线程"+i){
                public void run() {
                    try {
                        testSync();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
        System.out.println("主线程执行完毕!!!!");
    }
}


如上可以看到 LockSupport的park方法不释放锁

3.LockSupport对interrupt的感知 不需要抛异常直接被中断

package day03.part2;

import java.util.concurrent.locks.LockSupport;

/**
 * LockSupport对interrupt的感知
 * 不需要抛异常直接被中断
 * @author xzq
 */
public class LockSupportTest04 {

    public static void main(String[] args) {
        Thread t= new Thread("子线程"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+":开始执行……");
                System.out.println(threadName+":睡眠中……");
                /*synchronized (this) {
                    try {
                        //使用wait进行等待
                        this.wait();
                        //使用sleep进行等待
//                      Thread.sleep(Long.MAX_VALUE);
                    } catch (InterruptedException e) {
                        System.out.println(threadName+":捕获到中断异常……");
                    }
                }*/
                LockSupport.park();//被中断时不需要俘获异常
                System.out.println(threadName+":执行结束!");
            }

        };
        t.start();
        System.out.println("main:对子线程进行中断!");
        t.interrupt();
        System.out.println("main:执行结束……");
    }

}


4.用LockSupport实现非重入锁

package day03.part2;

import java.util.concurrent.locks.LockSupport;

/**
 * LockSupport的应用
 * 用LockSupport实现非重入锁
 * @author xzq
 */
public class LockSupportTest05 {

    private static MyLock lock=new MyLock();

    public static void main(String[] args) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":进入同步区域……");
        testSync_1();
        System.out.println(threadName+":离开同步区域……");
    }

    private static /*synchronized*/ void testSync_1(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":开始执行testSync_1方法……");
//      lock.lock();
        System.out.println(threadName+":准备进入testSync_2方法……");
        testSync_2();
        System.out.println(threadName+":执行了testSync_2中的逻辑!!!");
//      lock.unlock();
        System.out.println(threadName+":执行testSync_1方法结束!!!");
    }

    private static /*synchronized*/ void testSync_2(){
        String threadName = Thread.currentThread().getName();
//      lock.lock();
        System.out.println(threadName+":执行了testSync_2中的逻辑!!!");
//      lock.unlock();
    }



    static class MyLock{

        private boolean isLocked = false;

        public synchronized void lock(){
            while(isLocked){
                LockSupport.park();
            }
            isLocked = true;
        }

        public synchronized void unlock(){
            isLocked = false;
            LockSupport.unpark(Thread.currentThread());
        }
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值