史上最全synchronized用法详解

Java中synchronized关键字用于代码的同步执行,他可以修饰代码块、方法、this、Object.class,能够保证在多线程环境中只有线程执行。synchronized作用范围越小并发能力越强,下面我们就各种场景来详解举例说明。

多个synchronized(this)代码块并发执行

当一个线程访问类中的synchronized(this)的代码块时,该类中的其他synchronized(this)同步代码处于阻塞状态,例如:

class SynchronizedThis两个synchronized(this)同步代码块
public class SynchronizedThis {
    public void methodA(){
        synchronized(this){
            System.out.println("this A start:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("this A end:"+Thread.currentThread().getName());
        }
    }

    public void methodB(){
        synchronized(this){
            System.out.println("this B start:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("this B end:"+Thread.currentThread().getName());
        }
    }
}

两个线程类

public class MyThreadA implements Runnable {

    private SynchronizedThis sthis;

    public MyThreadA(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.methodA();
    }
}
public class MyThreadB implements Runnable {
private SynchronizedThis sthis;

    public MyThreadB(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.methodB();
    }
}

启动线程类

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        MyThreadB threadB = new MyThreadB(sthis);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,ThreadA运行完成之后ThreadB才能继续执行

this A start:A
this A end:A
this B start:B
this B end:B

synchronized(this)代码块与synchronized方法并发执行

当一个线程访问类中的synchronized(this)的代码块时,该类中的其他synchronized方法处于阻塞状态,例如:
class SynchronizedThis一个synchronized(this)同步代码块一个synchronized方法

public class SynchronizedThis {
    public synchronized void methodA(){
        System.out.println("this A start:"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("this A end:"+Thread.currentThread().getName());
    }

    public void methodB(){
        synchronized(this){
            System.out.println("this B start:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("this B end:"+Thread.currentThread().getName());
        }
    }
}

两个线程类和启动线程类同上
运行结果,线程A运行完成之后线程B才可以运行

this A start:A
this A end:A
this B start:B
this B end:B

synchronized(this)代码块与非synchronized方法并发执行

synchronized(this)代码块与非同步方法之间是不存在锁竞争的,可以并发执行,例如:

public class SynchronizedThis {
    public void methodA(){
        System.out.println("this A start:"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("this A end:"+Thread.currentThread().getName());
    }

    public void methodB(){
        synchronized(this){
            for(int i=0;i<5;i++){
                System.out.println("this B start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this B end:"+Thread.currentThread().getName());
            }
        }
    }
}

两个线程类和启动线程类同上
运行结果,线程A和线程B并发一起执行了

this A start:A
this B start:B0
this A end:A
this B end:B0
this B start:B1
this B end:B1
this B start:B2
this B end:B2
this B start:B3
this B end:B3
this B start:B4
this B end:B4

多个synchronized(任意对象)之间并发执行

public class SynchronizedThis {

    private String flag = new String();

    public void method(String name){
        synchronized(flag){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }
}

两个线程类

public class MyThreadA implements Runnable {

    private SynchronizedThis sthis;

    public MyThreadA(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.method("sunwukong");
    }
}
public class MyThreadB implements Runnable {
private SynchronizedThis sthis;

    public MyThreadB(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.method("zhubajie");
    }
}

启动线程类
同一个SynchronizedThis

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        MyThreadB threadB = new MyThreadB(sthis);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,线程B需要等待线程A运行完成之后才执行

this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B

多个SynchronizedThis

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        SynchronizedThis sthis2 = new SynchronizedThis();
        MyThreadB threadB = new MyThreadB(sthis2);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,由于锁定的对象不是同一个所以可以并发执行,不会阻塞,

this sunwukong start:A
this zhubajie start:B
this zhubajie end:B
this sunwukong end:A
this zhubajie start:B
this sunwukong start:A
this sunwukong end:A
this zhubajie end:B
this zhubajie start:B
this sunwukong start:A
this zhubajie end:B
this sunwukong end:A
this zhubajie start:B
this sunwukong start:A
this zhubajie end:B
this sunwukong end:A
this zhubajie start:B
this sunwukong start:A
this zhubajie end:B
this sunwukong end:A

这边需要注意的是如果synchronized(字符常量),无论new多少个对象都会阻塞不会并发执行,因为JVM维护了一个String,Integer等常量池,new新的对象他不会创建新的字符串,而是引用字符串常量池中已经存在的字符串。
注:synchronized(obj)obj不能是基本数据类型,可以包装数据类型
例如:

public class SynchronizedThis {

    private String flag = "flag";

    public void method(String name){
        synchronized(flag){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }
}
public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        SynchronizedThis sthis2 = new SynchronizedThis();
        MyThreadB threadB = new MyThreadB(sthis2);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果

this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B

上面的private String flag = new String();是个全局变量,如果我们改成局部变量,即使我们只new一个对象,也会并发执行,因为JVM会为每个线程分配一个私有的空间,TheadA和TheadB两个线程锁定的不是同一个flag,下面让我们来验证下:

public class SynchronizedThis {

    public void method(String name){
        String flag = new String();
        synchronized(flag){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }
}

线程类同上,直接看启动线程类

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        MyThreadB threadB = new MyThreadB(sthis);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,A和B并发执行了

this sunwukong start:A
this zhubajie start:B
this zhubajie end:B
this sunwukong end:A
this zhubajie start:B
this sunwukong start:A
this sunwukong end:A
this zhubajie end:B
this sunwukong start:A
this zhubajie start:B
this zhubajie end:B
this sunwukong end:A
this zhubajie start:B
this sunwukong start:A
this sunwukong end:A
this zhubajie end:B
this zhubajie start:B
this sunwukong start:A
this zhubajie end:B
this sunwukong end:A

synchronized(任意对象)与synchronized方法之间

public class SynchronizedThis {

    private Integer flag = new Integer(0);
    public void method(String name){
        synchronized(flag){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }

    public synchronized void method2(String name){
        System.out.println("this"+name+" start:"+Thread.currentThread().getName());
        System.out.println("this"+name+" end:"+Thread.currentThread().getName());
    }
}

两个线程类:

public class MyThreadA implements Runnable {

    private SynchronizedThis sthis;

    public MyThreadA(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.method("sunwukong");
    }
}
public class MyThreadB implements Runnable {
private SynchronizedThis sthis;

    public MyThreadB(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.method2("zhubajie");
    }
}

启动线程类

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        MyThreadB threadB = new MyThreadB(sthis);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,线程A和线程B可以并发异步执行,因为他们锁的对象不是一个,一个是flag,一个是当前实例this

this sunwukong start:A
thiszhubajie start:B
thiszhubajie end:B
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A

多个synchronized方法之间

public class SynchronizedThis {

    public synchronized void method(String name){
        for(int i=0;i<5;i++){
            System.out.println("this "+name+" start:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("this "+name+" end:"+Thread.currentThread().getName());
        }
    }

    public synchronized void method2(String name){
        System.out.println("this"+name+" start:"+Thread.currentThread().getName());
        System.out.println("this"+name+" end:"+Thread.currentThread().getName());
    }
}

两个线程类,线程启动类同上
运行结果,线程B需要等待线程A执行完成之后再执行,这是因为synchronized方法和synchronized(this)效果一样,都是锁定当前this

this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
thiszhubajie start:B
thiszhubajie end:B

synchronized方法与synchronized(*.class)

public class SynchronizedThis {

    public void method(String name){
        synchronized(SynchronizedThis.class){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }

    public synchronized void method2(String name){
        System.out.println("this"+name+" start:"+Thread.currentThread().getName());
        System.out.println("this"+name+" end:"+Thread.currentThread().getName());
    }
}

两个线程类

public class MyThreadA implements Runnable {

    private SynchronizedThis sthis;

    public MyThreadA(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.method("sunwukong");
    }
}
public class MyThreadB implements Runnable {
private SynchronizedThis sthis;

    public MyThreadB(SynchronizedThis sthis){
        this.sthis = sthis;
    }

    @Override
    public void run() {
        sthis.method2("zhubajie");
    }
}

线程启动类

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        MyThreadB threadB = new MyThreadB(sthis);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,线程A和线程B可以并发异步执行,他们一个锁的是this一个当前对象class

this sunwukong start:A
thiszhubajie start:B
thiszhubajie end:B
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A

静态synchronized方法与synchronized(*.class)

public class SynchronizedThis {

    public void method(String name){
        synchronized(SynchronizedThis.class){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }

    public static synchronized void method2(String name){
        System.out.println("this"+name+" start:"+Thread.currentThread().getName());
        System.out.println("this"+name+" end:"+Thread.currentThread().getName());
    }
}

两个线程类和线程启动类同上
运行结果,线程B需要等待线程A运行完成之后才能运行,因为静态静态方法添加synchronized之后锁定的是当前类.class

this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
thiszhubajie start:B
thiszhubajie end:B

synchronized(*.class)之间并发执行

public class SynchronizedThis {

    public void method(String name){
        synchronized(SynchronizedThis.class){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }

    public static synchronized void method2(String name){
        synchronized(SynchronizedThis.class){
            for(int i=0;i<5;i++){
                System.out.println("this "+name+" start:"+Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("this "+name+" end:"+Thread.currentThread().getName());
            }
        }
    }
}

线程启动类,我new一个对象

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        MyThreadB threadB = new MyThreadB(sthis);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,线程B需要等待线程A执行完之后才能执行

this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B

如果new两个对象

public class MainThread {
    public static void main(String[] args) {
        SynchronizedThis sthis = new SynchronizedThis();
        MyThreadA threadA = new MyThreadA(sthis);
        Thread TA = new Thread(threadA,"A");
        TA.start();
        SynchronizedThis sthis2 = new SynchronizedThis();
        MyThreadB threadB = new MyThreadB(sthis2);
        Thread TB = new Thread(threadB,"B");
        TB.start();
    }
}

运行结果,和new一个对象效果一样,说明synchronized(SynchronizedThis.class)是对JVM中所有对象实例加锁,后面我再写一篇文章介绍下synchronized在JVM中是怎么工作的

this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this sunwukong start:A
this sunwukong end:A
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B
this zhubajie start:B
this zhubajie end:B

总结(这里的同一个对象是指我上面的SynchronizedThis sthis = new SynchronizedThis();new了一个还是两个):
1、多个synchronized(this)
同一个对象:不能并发执行,不同对象:可以并发
2、synchronized(this)代码块与synchronized方法
同一个对象::两个加锁效果一样,不能并发执行;不同对象:可以并发
3、synchronized(任意对象)与synchronized方法
同一个对象:可以并发,不同对象:可以并发
4、多个synchronized方法
同一个对象:不能并发执行,不同对象:可以并发
5、synchronized方法与synchronized(*.class)
同一个对象:可以并发,不同对象:可以并发
6、静态synchronized方法与synchronized(*.class)
同一个对象:不能并发执行,不同对象:不能并发执行
7、synchronized(*.class)之间
同一个对象:不能并发执行,不同对象:不能并发执行
下篇文章我会对synchronized在JVM中怎么工作的进行详细讲解。

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值