文档章节

java并发编程,synchronized所有用法

郑加威
 郑加威
发布于 2018/03/17 12:08
字数 3094
阅读 375
收藏 4

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)之间 
同一个对象:不能并发执行,不同对象:不能并发执行 

 

© 著作权归作者所有

郑加威
粉丝 175
博文 183
码字总数 387300
作品 0
杭州
架构师
私信 提问
Java 并发编程源码解析汇总篇

java并发编程,内存模型 java并发编程,volatile内存实现和原理 Java并发编程,并发基础 Java 并发编程,线程池(ThreadPoolExecutor)源码解析 Java并发编程,Executor 框架介绍 Java并发编...

郑加威
2018/12/23
0
0
「原创」Java并发编程系列01 开篇获奖感言

  全网都是复制粘贴的文章,师长这里一直坚持输出原创   点击上方“java进阶架构师”,选择右上角“置顶公众号   不要错过每一天的原创!      为什么要学并发编程   我曾听一个...

java进阶架构师
09/28
0
0
再有人问你synchronized是什么,就把这篇文章发给他。

在《深入理解Java虚拟机》中,有这样一段话: synchronized关键字在需要原子性、可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的。的确,大部分并发控制操作...

Java填坑之路
2018/08/07
0
0
求你了,再问你Java内存模型的时候别再给我讲堆栈方法区了…

GitHub 4.1k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 4.1k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 4.1k Star 的Java工程师成神之路 ,真的确定不来了解一下吗...

Hollis
07/02
0
0
再有人问你volatile是什么,就把这篇文章发给他

Java语言为了解决并发编程中存在的原子性、可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized、volatile、final、concurren包等。在前一篇文章中,我们也介绍了syn...

Java小铺
2018/08/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

好程序员大数据教程分享Scala系列之模式匹配和样例类

好程序员大数据教程分享Scala系列之模式匹配和样例类 1.样例类 在Scala中样例类是一中特殊的类,样例类是不可变的, 可以通过值进行比较,可用于模式匹配。 定义一个样例类: 构造器中每一个...

好程序员官网
30分钟前
4
0
让nginx上的静态网页在访问的时候没有html后缀

需求背景: 公司产品小姐姐觉得这个访问带html后缀不专业,要求访问不带html后缀 nginx 配置 #原配置 location / { index index.html index.htm index.php; try_files $...

Linux_Anna
31分钟前
4
0
beetl的内置函数

函数调用Beetl内置函数请参考附录,以下列出了常用的函数date 返回一个java.util.Date类型的变量,如 date() 返回一个当前时间(对应java的java.util.Date); ${date( "2011-1-1" , "yy...

gantaos
32分钟前
4
0
spring cloud 2.x版本 Gateway自定义过滤器教程

前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 [toc] 本文基于前两篇文章eureka-server、eureka-client、eureka-ribbon、eureka-feign和spring-gataway的实现。 参考......

毛毛向前冲V5
35分钟前
4
0
VPGAME 的 Kubernetes 迁移实践

作者 | 伍冲斌 VPGAME 运维开发工程师 导读:VPGAME 是集赛事运营、媒体资讯、大数据分析、玩家社群、游戏周边等为一体的综合电竞服务平台。总部位于中国杭州,在上海和美国西雅图分别设立了...

阿里巴巴云原生
40分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部