欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

Java线程阻塞原语-LockSupport

发布时间:2024/4/13 java 83 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Java线程阻塞原语-LockSupport 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

在Java6引入LockSupport以前,线程挂起和唤醒要通过Object的wait和notify/notifyAllfangAll实现,但后者必须要在同步块里调用,且notify必须要在wait之后调用才行否则会导致线程阻塞。

LockSupport比Object的wait/notify有两大优势:

  • LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。
  • unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序。
  • LockSupport原理

    LockSupport和每个使用它的线程都与一个许可(permit)关联。permit类似信号量,相当于1,0的开关,默认是0(表示许可是被占用的,调用park()会阻塞),调用一次unpark被置为1,调用一次park会消费permit, 也就是将1变成0,同时park立即返回。再次调用park会变成block(因为permit为0了,会阻塞在这里,直到permit变为1), 这时调用unpark会把permit置为1。每个线程都有一个相关的permit, permit最多只有一个,重复调用unpark也不会积累

    park()和unpark()不会有 “Thread.suspend和Thread.resume所可能引发的死锁” 问题,由于许可的存在,调用 park 的线程和另一个试图将其 unpark 的线程之间的竞争将保持活性

    许可默认是占用的

    public static void main(String[] args)
    {
       LockSupport.park();      //此处阻塞,因为许可默认占用
       System.out.println("block.");
    }

     

    public static void main(String[] args)
    {
       Thread thread = Thread.currentThread();
       LockSupport.unpark(thread);          //释放许可
       LockSupport.park();                        // 获取许可,此处不阻塞,继续运行
       System.out.println("b");
    }

     

    LockSupport不可重入

    public static void main(String[] args) throws Exception
    {
     Thread thread = Thread.currentThread();
     
     LockSupport.unpark(thread);  //释放许可
     
     System.out.println("a");
     LockSupport.park();               // 获取许可,此处不阻塞,继续运行
     System.out.println("b");
     LockSupport.park();              // 获取不到许可,此处阻塞
     System.out.println("c"); 
    }

    对中断的响应

    线程如果因为调用park而阻塞的话,能够响应中断请求,park()方法返回不再阻塞,中断状态被设置成true,但是不会抛出InterruptedException。

    LockSupport函数列表

    // 返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。 static Object getBlocker(Thread t) // 为了线程调度,禁用当前线程,除非许可可用。 static void park() // 为了线程调度,在许可可用之前禁用当前线程 static void park(Object blocker) // 为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。 static void parkNanos(long nanos) // 为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。 static void parkNanos(Object blocker, long nanos) // 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。 static void parkUntil(long deadline) // 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。 static void parkUntil(Object blocker, long deadline) // 如果给定线程的许可尚不可用,则使其可用。(释放许可) static void unpark(Thread thread)

    blocker:这个对象是用来记录线程被阻塞时被谁阻塞的。

    相对时间与绝对时间

    LockSupport的park()函数调用了unsafe.park()方法。

    public static void park() {unsafe.park(false, 0L);}public static void parkNanos(long nanos) {if (nanos > 0)unsafe.park(false, nanos);}public static void parkUntil(long deadline) {unsafe.park(true, deadline);} //Unsafe public native void park(boolean isAbsolute, long time);
    • nanos:在nanos时间后线程自动恢复挂起

    • deadline:在deadline时刻线程自动(这个毫秒其实就是自1970年1月1日0时起的毫秒数)

    park方法是一个阻塞的方法,除非4个条件

  • 当配对的unpark发生

  • 线程被中断时恢复

  • 阻塞时间已过

    • 当absolute是false时,如果给定的时间是非0(负数)或者给定的时间(正数, 时间单位时毫秒)已经过去了(0的时候会一直阻塞着)。
    • 当Absolute是true时,如果给定的时间(时间单位是纳秒)过去了或者伪造的(在我理解是参数不合法时)线程会恢复中断。

     

     

     

     

     

     

    总结

    以上是生活随笔为你收集整理的Java线程阻塞原语-LockSupport的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。