源码解析Synchronized同步方法的八种使用场景,收藏

简介

本文将介绍8种同步方法的访问场景,我们来看看这八种情况下,多线程访问同步方法是否还是线程安全的。这些场景是多线程编程中经常遇到的,而且也是面试时高频被问到的问题,所以不管是理论还是实践,这些都是多线程场景必须要掌握的场景。

好了,话不多说,看正文吧,关注公众号:Java架构师联盟

场景一:两个线程同时访问同一个对象的同步方法

分析:这种情况是经典的对象锁中的方法锁,两个线程争夺同一个对象锁,所以会相互等待,是线程安全的。

代码实现

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n37950" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:27
  • @description:两个线程同时访问同一个对象的同步方法
    */

    public class Condition1 implements Runnable {

    private static Condition1 instance = new Condition1();

    @Override
    public void run() {
    method();
    }

    //关键:synchronized可以保证此方法被顺序执行,线程1执行完4秒钟后,线程2再执行4秒。不加synchronized,线程1和线程2将同时执行
    private synchronized void method() {
    System.out.println("线程:" + Thread.currentThread().getName() + ",运行开始");
    try {
    //模拟执行一段操作,耗时4秒钟
    Thread.sleep(4000);
    System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    public static void main(String[] args) {
    // 模拟:同一个对象下,两个线程,同步执行一个方法(串行执行则为线程安全,并行执行,则为线程不安全,)
    Thread thread1 = new Thread(instance);
    Thread thread2 = new Thread(instance);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()) {

    }
    System.out.println("测试结束");
    }
    }</pre>

运行结果

源码解析Synchronized同步方法的八种使用场景,收藏

结果分析

发现运行结果中,多个线程也是串行执行的,效果跟同步代码块锁是一致的。

场景二:两个线程同时访问两个对象的同步方法

这种场景就是对象锁失效的场景,原因出在访问的是两个对象的同步方法,那么这两个线程分别持有的两个线程的锁,所以是互相不会受限的。加锁的目的是为了让多个线程竞争同一把锁,而这种情况多个线程之间不再竞争同一把锁,而是分别持有一把锁

代码验证:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n37959" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:10
  • @description:两个线程同时访问两个对象的同步方法
    */

    public class Condition2 implements Runnable {
    // 创建两个不同的对象
    static Condition2 instance1 = new Condition2();
    static Condition2 instance2 = new Condition2();

    @Override
    public void run() {
    method();
    }

    private synchronized void method() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
    }

    public static void main(String[] args) {
    Thread thread1 = new Thread(instance1);
    Thread thread2 = new Thread(instance2);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()) {
    }
    System.out.println("测试结束");
    }
    }</pre>

运行结果:

两个线程是并行执行的,所以线程不安全。

源码解析Synchronized同步方法的八种使用场景,收藏

代码分析:

「问题在此:」两个线程(thread1、thread2),访问两个对象(instance1、instance2)的同步方法(method()),两个线程都有各自的锁,不能形成两个线程竞争一把锁的局势,所以这时,synchronized修饰的方法method()和不用synchronized修饰的效果一样(不信去把synchronized关键字去掉,运行结果一样),所以此时的method()只是个普通方法。

「如何解决这个问题:」若要使锁生效,只需将method()方法用static修饰,这样就形成了类锁,多个实例(instance1、instance2)共同竞争一把类锁,就可以使两个线程串行执行了。

场景三:两个线程同时访问(一个或两个)对象的静态同步方法

这个场景解决的是场景二中出现的线程不安全问题,即用类锁实现

代码实现

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n37970" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:32
  • @description:静态方法锁的方式实现类锁
    */


    public class Condition3 implements Runnable {

    // 这两个实例,声明为static,是因为要在main方法中测试,与方法锁无关
    static Condition3 instance1 = new Condition3();
    static Condition3 instance2 = new Condition3();

    // 关键: static synchronized两个关键字同时使用
    private static synchronized void method() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
    }

    @Override
    public void run() {
    method();
    }

    public static void main(String[] args) {
    Thread thread1 = new Thread(instance1);
    Thread thread2 = new Thread(instance2);
    thread1.start();
    thread2.start();
    try {
    //两个线程必须都执行完毕后
    thread1.join();
    thread2.join();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("两个线程都已经执行完毕");
    }
    }</pre>

结果展示

源码解析Synchronized同步方法的八种使用场景,收藏

场景四:两个线程分别同时访问(一个或两个)对象的同步方法和非同步方法

这个场景是两个线程其中一个访问同步方法,另一个访问非同步方法,此时程序会不会串行执行呢,也就是说是不是线程安全的呢?我们可以确定是线程不安全的,如果方法不加synchronized都是安全的,那就不需要同步方法了。

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n37976" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:12
  • @description:两个线程同时访问(一个或两个)对象的静态同步方法
    */

    public class Condition4 implements Runnable {

    static Condition4 instance = new Condition4();

    @Override
    public void run() {
    //两个线程访问同步方法和非同步方法
    if (Thread.currentThread().getName().equals("Thread-0")) {
    //线程0,执行同步方法method0()
    method0();
    }
    if (Thread.currentThread().getName().equals("Thread-1")) {
    //线程1,执行非同步方法method1()
    method1();
    }
    }

    // 同步方法
    private synchronized void method0() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",同步方法,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",同步方法,运行结束");
    }

    // 普通方法
    private void method1() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",普通方法,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",普通方法,运行结束");
    }

    public static void main(String[] args) {
    Thread thread1 = new Thread(instance);
    Thread thread2 = new Thread(instance);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()) {
    }
    System.out.println("测试结束");
    }

    }</pre>

运行结果:

两个线程是并行执行的,所以是线程不安全的。

源码解析Synchronized同步方法的八种使用场景,收藏

结果分析

「问题在于此:」 method1没有被synchronized修饰,所以不会受到锁的影响。即便是在同一个对象中,当然在多个实例中,更不会被锁影响了。

场景五:两个线程访问同一个对象中的同步方法,同步方法又调用一个非同步方法

我们来实验下这个场景,用两个线程调用同步方法,在同步方法中调用普通方法;再用一个线程直接调用普通方法,看看是否是线程安全的?

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n37985" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:14
  • @description:两个线程访问同一个对象中的同步方法,同步方法又调用一个非同步方法
    */


    public class Condition5 implements Runnable {

    static Condition5 instance = new Condition5();

    @Override
    public void run() {
    if (Thread.currentThread().getName().equals("Thread-0")) {
    //直接调用普通方法
    method2();
    } else {
    // 先调用同步方法,在同步方法内调用普通方法
    method1();
    }
    }

    // 同步方法
    private static synchronized void method1() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",同步方法,运行开始");
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",同步方法,运行结束,开始调用普通方法");
    method2();
    }

    // 普通方法
    private static void method2() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",普通方法,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",普通方法,运行结束");
    }

    public static void main(String[] args) {
    // 此线程直接调用普通方法
    Thread thread0 = new Thread(instance);
    // 这两个线程直接调用同步方法
    Thread thread1 = new Thread(instance);
    Thread thread2 = new Thread(instance);
    thread0.start();
    thread1.start();
    thread2.start();
    while (thread0.isAlive() || thread1.isAlive() || thread2.isAlive()) {
    }
    System.out.println("测试结束");
    }

    }</pre>

运行结果:

源码解析Synchronized同步方法的八种使用场景,收藏

结果分析:

我们可以看出,普通方法被两个线程并行执行,不是线程安全的。这是为什么呢?

因为如果非同步方法,有任何其他线程直接调用,而不是仅在调用同步方法时,才调用非同步方法,此时会出现多个线程并行执行非同步方法的情况,线程就不安全了。

对于同步方法中调用非同步方法时,要想保证线程安全,就必须保证非同步方法的入口,仅出现在同步方法中。但这种控制方式不够优雅,若被不明情况的人直接调用非同步方法,就会导致原有的线程同步不再安全。所以不推荐大家在项目中这样使用,但我们要理解这种情况,并且我们要用语义明确的、让人一看就知道这是同步方法的方式,来处理线程安全的问题。

所以,最简单的方式,是在非同步方法上,也加上synchronized关键字,使其变成一个同步方法,这样就变成了《场景五:两个线程同时访问同一个对象的不同的同步方法》,这种场景下,大家就很清楚的看到,同一个对象中的两个同步方法,不管哪个线程调用,都是线程安全的了。

场景六:两个线程同时访问同一个对象的不同的同步方法

这个场景也是在探讨对象锁的作用范围,对象锁的作用范围是对象中的所有同步方法。所以,当访问同一个对象中的多个同步方法时,结论是:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n37996" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:16
  • @description:两个线程同时访问同一个对象的不同的同步方法
    */

    public class Condition6 implements Runnable {
    static Condition6 instance = new Condition6();

    @Override
    public void run() {
    if (Thread.currentThread().getName().equals("Thread-0")) {
    //线程0,执行同步方法method0()
    method0();
    }
    if (Thread.currentThread().getName().equals("Thread-1")) {
    //线程1,执行同步方法method1()
    method1();
    }
    }

    private synchronized void method0() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",同步方法0,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",同步方法0,运行结束");
    }

    private synchronized void method1() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",同步方法1,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",同步方法1,运行结束");
    }

    //运行结果:串行
    public static void main(String[] args) {
    Thread thread1 = new Thread(instance);
    Thread thread2 = new Thread(instance);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()) {
    }
    System.out.println("测试结束");
    }
    }</pre>

运行结果:

源码解析Synchronized同步方法的八种使用场景,收藏

结果分析:

两个方法(method0()和method1())的synchronized修饰符,虽没有指定锁对象,但默认锁对象为this对象为锁对象, 所以对于同一个实例(instance),两个线程拿到的锁是同一把锁,此时同步方法会串行执行。这也是synchronized关键字的可重入性的一种体现。

场景七:两个线程分别同时访问静态synchronized和非静态synchronized方法

这种场景的本质也是在探讨两个线程获取的是不是同一把锁的问题。静态synchronized方法属于类锁,锁对象是(*.class)对象,非静态synchronized方法属于对象锁中的方法锁,锁对象是this对象。两个线程拿到的是不同的锁,自然不会相互影响。

代码实现:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n38005" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:20
  • @description:两个线程分别同时访问静态synchronized和非静态synchronized方法
    /


    public class Condition7 implements Runnable {
    static Condition7 instance = new Condition7();

    @Override
    public void run() {
    if (Thread.currentThread().getName().equals("Thread-0")) {
    //线程0,执行静态同步方法method0()
    method0();
    }
    if (Thread.currentThread().getName().equals("Thread-1")) {
    //线程1,执行非静态同步方法method1()
    method1();
    }
    }

    // 重点:用static synchronized 修饰的方法,属于类锁,锁对象为(
    .class)对象。
    private static synchronized void method0() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",静态同步方法0,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",静态同步方法0,运行结束");
    }

    // 重点:synchronized 修饰的方法,属于方法锁,锁对象为(this)对象。
    private synchronized void method1() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",非静态同步方法1,运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",非静态同步方法1,运行结束");
    }

    //运行结果:并行
    public static void main(String[] args) {
    //问题原因: 线程1的锁是类锁(*.class)对象,线程2的锁是方法锁(this)对象,两个线程的锁不一样,自然不会互相影响,所以会并行执行。
    Thread thread1 = new Thread(instance);
    Thread thread2 = new Thread(instance);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()) {
    }
    System.out.println("测试结束");
    }
    }</pre>

运行结果:

源码解析Synchronized同步方法的八种使用场景,收藏

场景八:同步方法抛出异常后,JVM会自动释放锁的情况

本场景探讨的是synchronized释放锁的场景:

所以,在一个线程的同步方法中出现异常的时候,会释放锁,另一个线程得到锁,继续执行。而不会出现一个线程抛出异常后,另一个线程一直等待获取锁的情况。这是因为JVM在同步方法抛出异常的时候,会自动释放锁对象。

代码实现:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n38013" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.syn;

/**

  • @author :biws
  • @date :Created in 2020/12/21 22:22
  • @description:同步方法抛出异常后,JVM会自动释放锁的情况
    */


    public class Condition8 implements Runnable {

    private static Condition8 instance = new Condition8();

    @Override
    public void run() {
    if (Thread.currentThread().getName().equals("Thread-0")) {
    //线程0,执行抛异常方法method0()
    method0();
    }
    if (Thread.currentThread().getName().equals("Thread-1")) {
    //线程1,执行正常方法method1()
    method1();
    }
    }

    private synchronized void method0() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    //同步方法中,当抛出异常时,JVM会自动释放锁,不需要手动释放,其他线程即可获取到该锁
    System.out.println("线程名:" + Thread.currentThread().getName() + ",抛出异常,释放锁");
    throw new RuntimeException();

    }

    private synchronized void method1() {
    System.out.println("线程名:" + Thread.currentThread().getName() + ",运行开始");
    try {
    Thread.sleep(4000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("线程:" + Thread.currentThread().getName() + ",运行结束");
    }

    public static void main(String[] args) {
    Thread thread1 = new Thread(instance);
    Thread thread2 = new Thread(instance);
    thread1.start();
    thread2.start();
    while (thread1.isAlive() || thread2.isAlive()) {
    }
    System.out.println("测试结束");
    }

    }</pre>

运行结果:

源码解析Synchronized同步方法的八种使用场景,收藏

结果分析:

可以看出线程还是串行执行的,说明是线程安全的。而且出现异常后,不会造成死锁现象,JVM会自动释放出现异常线程的锁对象,其他线程获取锁继续执行。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容