上面的例子是Synchronized关键字的使用方式之一,此时,synchronized标记的是类的实例方法,锁对象是类的实例对象。当然还有其他使用方式:

 private static synchronized void test() {
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.MILLISECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(num++);
        }
    }

此时,synchronized标记的是类的静态方法,锁对象是类。

以上两种,是直接标记在方法上。

还可以包裹代码块:

    private void test() {
        synchronized (Main.class) {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.MILLISECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(num++);
            }
        }
    }

此时锁的对象是 类。

    private void test() {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.MILLISECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(num++);
            }
        }
    }

此时锁的对象是类的实例对象。

    private Object object = new Object();

    private void test() {
        synchronized (object) {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.MILLISECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(num++);
            }
        }
    }

此时,锁对象是Object的对象。

JConsole探究Synchronized关键字

我们需要用到JDK自带的一个工具:JConsole,它位于JDK的bin目录下。

为了让观察更加方便,我们需要给线程起一个名字,每个线程内sleep的时间稍微长一点:

public class Main {
    private synchronized void test() {
        try {
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Main main = new Main();
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                main.test();
            }, "Hello,Thread " + i).start();
        }
    }
}

我们先启动项目,然后打开JConsole,找到你项目的进程,就可以连接上去了。

可以看到,5个线程已经显示在JConsole里面了:

四脚猫PHP高级课程

点击某个线程,可以看到关于线程的一些信息:

四脚猫PHP高级课程

四脚猫PHP高级课程

其中四个线程都处于BLOCKED,只有一个处于TIME_WAITING,说明只有一个线程获得了锁,并在TIME_WAITING,其余的线程都没有获得锁,没有进入到方法,说明了Synchronized的互斥性。关于线程的状态,这篇不会深入,以后可能会介绍这方面的知识。

因为我是一边写博客,一边执行各种操作的,所以速度上有些跟不上,导致截图和描述不同,大家可以自己去试试。

javap探究Synchronized关键字

为了把问题简单化,让大家看的清楚,我只保留synchronized相关的代码:

public class Main {
    public static void main(String[] args) {
        synchronized (Main.class) {
        }
    }
}

编译后,用javap命令查看字节码文件:

javap -v Main.class

四脚猫PHP高级课程

用红圈圈出来的就是添加synchronized后带来的命令了。执行同步代码块,先是调用monitorenter命令,执行完毕后,再调用monitorexit命令,为什么会有两个monitorexit呢,一个是正常执行办法后的monitorexit,一个是发生异常后的monitorexit。

相关文章:

  • 2022-02-07
  • 2022-02-07
  • 2022-12-23
  • 2022-12-23
  • 2021-12-09
  • 2021-05-02
  • 2021-10-24
  • 2022-03-01
猜你喜欢
  • 2021-05-11
  • 2021-05-25
  • 2021-12-12
  • 2021-06-13
  • 2022-02-01
  • 2021-10-11
  • 2022-03-04
相关资源
相似解决方案