史上最全synchronized用法详解

时间:2022-03-17 04:03:34

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中怎么工作的进行详细讲解。