zoukankan      html  css  js  c++  java
  • 关于join() 是否会释放锁的一些思考

    # 首先从一个很有意思的问题开始:

      - 问 : Thread 的join() 方法是否会释放锁?

      - 答: 会!

    # 如果一切到这里就结束了,那可能也就没有这篇小记了,但是我的脑子却冒出了一些奇怪的想法:

      - 释放哪个对象的锁呢?

      - 难道是释放父线程所持有的所有对象的锁?

      -- 其实如果看了源码,很容易明白释放的是运行(这个地方可能有些歧义,但是我也不知道怎么说最好)join()方法的那个线程对象的锁,不过这些都是后话,我们且往下看;

    # 然后我就写了代码来验证一下我的猜想, 代码如下:

    public class QQ {
    
        public static void main(String[] args) {
            Object oo = new Object();
    
            Thread thread1 = new MyThread("thread1 -- ", oo);
            thread1.start();
    
            synchronized (oo) {
                for (int i = 0; i < 100; i++) {
                    if (i == 20) {
                        try {
                            thread1.join();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " -- " + i);
                }
            }
        }
    
    }
    
    class MyThread extends Thread {
    
        private String name;
        private Object oo;
    
        public MyThread(String name, Object oo) {
            this.name = name;
            this.oo = oo;
        }
    
        @Override
        public void run() {
            synchronized (oo) {
                for (int i = 0; i < 100; i++) {
                    System.out.println(name + i);
                }
            }
        }
    
    }

      - 运行一下,输出到 main -- 19 的时候,卡住了。

      - 接下来我们来寻找卡住的原因;

      -- 先使用jps找到出问题程序的进程号

      -- jstack pid 来查看线程堆栈,结果如下图

    "Thread-1" #14 prio=5 os_prio=0 tid=0x0000000018fa9000 nid=0x3f80 waiting for monitor entry [0x0000000019b0f000]
       java.lang.Thread.State: BLOCKED (on object monitor)
            - waiting to lock <0x00000000d8a06298> (a java.lang.Object)
    
    
    "main" #1 prio=5 os_prio=0 tid=0x000000000228e800 nid=0x3d6c in Object.wait() [0x00000000028af000]
       java.lang.Thread.State: WAITING (on object monitor)
            - locked <0x00000000d8a06298> (a java.lang.Object)

      -- 上图中我删掉了很多东西,只留下了一些关键的部分;首先我们看到 Thread-1 和 main 都在 waiting 状态,然后再注意到 Thread-1 在等待锁 <0x00000000d8a06298>,

    但是main持有锁<0x00000000d8a06298>, 这又是什么情况呢? 难道 main 没有释放锁?

      - 这时候我们就回到了最初的问题,到底join()的时候释放的是谁的锁,通过查看join()方法的源码,很容易看到,其实调用的是 this.wait(),也就是说释放的是Thread-1 这个对象的锁

    # 接着我们来用下面的代码证实一下我们得出的结论

    public class QQ {
    
        public static void main(String[] args) {
            Object oo = new Object();
    
            Thread thread1 = new MyThread("thread1 -- ", oo);
            thread1.start();
    
            synchronized (thread1) {
                for (int i = 0; i < 100; i++) {
                    if (i == 20) {
                        try {
                            thread1.join();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " -- " + i);
                }
            }
        }
    
    }
    
    class MyThread extends Thread {
    
        private String name;
        private Object oo;
    
        public MyThread(String name, Object oo) {
            this.name = name;
            this.oo = oo;
        }
    
        @Override
        public void run() {
            synchronized (this) {
                for (int i = 0; i < 100; i++) {
                    System.out.println(name + i);
                }
            }
        }
    
    }

      - 很容易验证我们的猜想和理解是正确的

    # 再接下来我们看一下如果调用wait() 方法,应该是怎么个情况呢;

    public class QQ {
    
        public static void main(String[] args) {
            Object oo = new Object();
    
            Thread thread1 = new MyThread("thread1 -- ", oo);
            thread1.start();
    
            synchronized (oo) {
                for (int i = 0; i < 100; i++) {
                    if (i == 20) {
                        try {
                            oo.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " -- " + i);
                }
            }
        }
    
    }
    
    class MyThread extends Thread {
    
        private String name;
        private Object oo;
    
        public MyThread(String name, Object oo) {
            this.name = name;
            this.oo = oo;
        }
    
        @Override
        public void run() {
            synchronized (oo) {
                for (int i = 0; i < 100; i++) {
                    System.out.println(name + i);
                }
                oo.notifyAll();
            }
        }
    
    }

      - 乍一看,和调用join() 方法的现象一样; 

      - 嗯。。。有点意思了。。。

    # 最后补充一点:jstack中的Thread-1 和 我们自己定义的 thread1 是不一样的,如果想要在jstack中显示我们自己定义的线程名, 则需要调用Thread的setName()方法

  • 相关阅读:
    Java设计模式--Java Builder模式
    Android网络开发之OkHttp--基本用法实例化各个对象
    Android网络开发之OkHttp--基本用法POST
    Android网络开发之OkHttp--基本用法GET
    Eclipse开发工具的使用之-使用Eclipse的Debug调试Android程序
    Android网络开发之Volley--Volley自定义Request
    弹出软键盘时,不把activity整体往上移,只移动部分
    圆角背景实现,如实现圆角按钮;用xml文件画圆
    在java代码中设置TextView文本内容可滚动
    Android模拟HOME键的效果
  • 原文地址:https://www.cnblogs.com/lwmp/p/11805440.html
Copyright © 2011-2022 走看看