欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

六、LockSupport

程序员文章站 2022-06-28 16:16:54
1、为什么使用LockSupport类如果只是LockSupport在使用起来比Object的wait/notify简单,那还真没必要专门讲解下LockSupport。最主要的是灵活性。①LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。②unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。上边的例子代码中,主线程调用了Thread.sleep(1000)方法来等待线程A计算完成进入wait状态。如果去掉Threa...

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());
        }
    }

}


本文地址:https://blog.csdn.net/XZQ_STUD/article/details/112251920

相关标签: 多线程