• 自己动手写java锁


    1、LockSupport的park和unpark方法的基本使用,以及对线程中断的响应性

    LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞原语。java锁和同步器框架的核心AQS:AbstractQueuedSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒的。LockSupport很类似于二元信号量(只有1个许可证可供使用),如果这个许可还没有被占用,当前线程获取许可并继续执行;如果许可已经被占用,当前线程阻塞,等待获取许可。注意:许可默认是被占用的。

    public static void main(String[] args)  {  

         LockSupport.park();  

         System.out.println("block.");  

    运行该代码,可以发现主线程一直处于阻塞状态,不会输出block.。因为许可默认是被占用的,调用park()时获取不到许可,所以进入阻塞状态。需要注意的是,尝试获取许可证的是调用了 LockSupport.park()方法的线程。

    LockSupport.unpark(Thread thread)方法需要传入一个线程作为参数,该方法的作用是允许作为参数的线程获取许可证,也就是唤醒作为参数的线程。public static void main(String[] args)  {  

         Thread thread = Thread.currentThread();  

         LockSupport.unpark(thread);//释放许可  

         LockSupport.park();// 获取许可  

         System.out.println("b");  

    }

    LockSupport是不可重入的,如果一个线程连续2次调用LockSupport.park(),那么该线程一定会一直阻塞下去。

    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");  

    }

    这段代码打印出a和b,不会打印c,因为第二次调用park的时候,线程无法获取许可出现死锁。

    1.1、LockSupport对中断的响应性

    LockSupport.park()能响应中断,也就是说A线程调用了LockSupport.park()方法被阻塞后,其他线程调用了A线程的interrupt()方法给A线程发送中断信号时,A线程的阻塞状态会被中断,继续执行。当然了,调用了了某线程的interrupt()方法后,该线程的中断状态isInterrupted()会由false变为true。

    public static void main(String[] args) {
      Thread t = new Thread(new Runnable() {
        private int count = 0;
        @Override
        public void run() {
          long start = System.currentTimeMillis();
          long end = 0;
          while ((end - start) <= 1000) {
            count++;
            end = System.currentTimeMillis();
          }
          System.out.println("after 1 second.count=" + count);
          System.out.println("thread " + Thread.currentThread().isInterrupted());
          //等待或许许可
          LockSupport.park();
          System.out.println("thread over." + Thread.currentThread().isInterrupted());
        }
      });
      t.start();
      try {
        Thread.sleep(8000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("向调用LockSupport.park()方法被阻塞的线程发送中断信号");
      // 中断线程
      t.interrupt();
      try {
        Thread.sleep(8000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println("main over");
    }

    最终线程会打印出thread over.true。这说明线程如果因为调用LockSupport.park()而阻塞的话,能够响应中断请求(中断状态被设置成true),但是不会抛出InterruptedException。

    2、Thread详解

    isInterrupted()  只获取线程的中断状态,返回值为线程的中断状态(每个线程都有一个中断状态标志位,用于表明当前线程是否处于中断状态)

    interrupted()  获取线程的中断状态,并清空状态(即如果线程的中断状态为true,则将其设置为false;如果线程的中断状态为false,则什么也不做),返回值为清空状态前线程的中断状态

    一般调用Thread的interrupt()会有两种处理方式:

    (1)遇到一个低优先级的block状态时,比如object.wait(),object.sleep(),object.join()导致线程阻塞,它会立马触发一个unblock解除阻塞,并在线程阻塞的位置抛出一个InterruptedException,此时当前线程的中断状态标志为false

    (2)其他情况导致的线程阻塞,Thread的interrupt()仅仅是更新了线程的中断状态标志位。然后线程继续执行,当然你也可以通过Thread.isInterrrupted()进行检查,做相应的处理,比如也抛出InterruptedException或者是清理状态,取消task等。 

  • 相关阅读:
    1-13Object类之toString方法
    jvm源码解读--16 锁_开头
    jvm源码解读--16 cas 用法解析
    jvm源码解读--15 oop对象详解
    jvm源码解读--14 defNewGeneration.cpp gc标记复制之后,进行空间清理
    jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析
    Error: Could not find or load main class ***
    使用javah 给.class类编译jni_helloworld.h文件头
    jvm源码解读--12 invokspecial指令的解读
    jvm源码解读--11 ldc指令的解读
  • 原文地址:https://www.cnblogs.com/jiangwangxiang/p/9159120.html
Copyright © 2020-2023  润新知