zoukankan      html  css  js  c++  java
  • LockSupport

    1、为什么想着了解LockSupport ?

    因为 LockSupport 在底层的使用较多,它比内置锁( synchronized 隐式锁)使用起来更方便。通常使用的“等待——通知”有3种 (还可通过Atomic类实现):

      (1) ReetrantLock 提供了一个 newCondition 方法 获取到 ConditionObject对象,通过condition, 我们可以调用 await() 和 signal 方法;

          (2) 通过调用Object的 wait 和 notify 方法。 wait和notifyAll必须写在同步代码块中,而同步一般用 synchronized ,JDK1.8及更高的版本也推荐使用 synchronized ;

          (3) 通过 LockSupport 调用 park 和 unpark 方法;

      具体什么情况下使用什么方式,需我们充分了解 这3种方式的优缺点。

    通过第2种方式实现:

    public static void main(String[] args) throws InterruptedException {
            final Object obj = new Object();    
            Thread son = new Thread(new Runnable() {
                public void run() {
                    try {
                        synchronized (obj) {
                            obj.wait();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("son thread");
                }
            });
            son.start();
            Thread.sleep(100); //阻塞wait方法
            synchronized (obj) {
                obj.notifyAll();
            }
        }

    缺点:当我们注释掉sleep后,可能线程son一直处于运行中,因为son线程不是后台线程。

    通过第3种方式实现:

    public static void main(String[] args) throws InterruptedException {
            Thread son = new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.park();
                    System.out.println("son thread");
                }
            });
            son.start();
            Thread.sleep(100);   
            LockSupport.unpark(son);
        }

    通过测试,主线程不执行sleep,son线程也会正常执行退出。这就是LockSupport的灵活性。

    2、jdk中哪些类使用了LockSupport 

        (1)我们在实现一个线程时,如果我们需要线程返回结果,那么我们要实现callable。我们通过Future取到返回值。

    public static void main(String[] args) throws InterruptedException, ExecutionException {
            ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
            ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 4, 100, TimeUnit.SECONDS, queue);
            
            Future<String> future = pool.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    TimeUnit.MILLISECONDS.sleep(100);
                    return UUID.randomUUID().toString();
                }
            });
            String result = future.get();  
            System.out.println(result);
        }

    上面一段代码,当我们在使用future.get时,如果线程还没执行完,那么程序是不是有问题? 还是它会阻塞,等到线程执行完?

    通过查看源码,可以找到结果。

    继续深入awaitDone方法

    可以看到awaitDone调用了LockSupport方法实现阻塞效果。那么线程怎么唤醒阻塞的线程了???  当然是通过 run() 方法,猜想run执行完之后,通知等待线程。

    查看set方法:

    查看finishCompletion方法:

    可以看到通知是用的unpark. 

      (2)上面main函数中使用了同步容器,其实jdk中容器都包含一个对象 Condition , Condition是个接口,它的实现类为ConditionObject。同步容器中维护了2个condition:notEmpty和notFull,调用await(),实际上就是ConditionObject的await()方法。

    await()

    另外:ConditionObject是 AbstractQueuedSynchronizer (AQS)的一个内部类。

     3、LockSupport源码

      lockSupport方法中调用的是 UNSAFE的native方法,需要openJDK查看。

    park底层代码:

     

  • 相关阅读:
    HTML DOM 事件
    js实现键盘数字输入
    js实现键盘数字输入
    onbeforeunload事件兼容性操作
    onbeforeunload事件兼容性操作
    window.event对象详尽解析
    git简单使用教程
    PHP中奖概率写法
    PHP替代session的方法
    nginx实现负载均衡
  • 原文地址:https://www.cnblogs.com/greys/p/10775635.html
Copyright © 2011-2022 走看看