synchronized
synchronized基础特性
- Synchronized是Java中的一个关键字
- 非公平锁,互斥锁
- 修饰的对象主要是方法和代码块
- 方法
非静态方法: 锁住的是当前实例对象
静态方法:当前类的Class实例
- 代码块
this: 锁住的是当前实例对象
实例对象: 锁住的是当前实例对象
class: 当前类的Class实例
synchronized具体示例
1. 无synchronized关键字
private static int count = 0;
public static void main(String[] args) {
noSync();
}
public static void noSync(){
SynchronizedTest test = new SynchronizedTest();
for (int i = 0; i < 5; i ++) {
Thread thread = new Thread(() -> {
test.testNoSync();
});
thread.start();
}
}
public void testNoSync(){
System.out.println(String.format("testNoSync:%s 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testNoSync:%s 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
count没有按0~5的顺序打印出来;线程无法保证有序count最终不为5,线程不安全
2. 方法上加synchronized关键字,线程间共同一个实例对象
private static int count = 0;
public static void main(String[] args) {
methodSingleSync();
}
public static void methodSingleSync(){
SynchronizedTest test = new SynchronizedTest();
for (int i = 0; i < 5; i ++) {
Thread thread = new Thread(() -> {
test.testMethodSingleSync();
});
thread.start();
}
}
public synchronized void testMethodSingleSync(){
System.out.println(String.format("testMethodSingleSync:%s 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testMethodSingleSync:%s 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
count按0~5的顺序打印出来,线程间串行执行count最终为5,线程安全
3. 方法上加synchronized关键字,线程间各自有一个实例对象
private static int count = 0;
public static void main(String[] args) {
methodMultiSync();
}
public static void methodMultiSync(){
for (int i = 0; i < 5; i ++) {
SynchronizedTest test = new SynchronizedTest();
Thread thread = new Thread(() -> {
test.testMethodMultiSync();
});
thread.start();
}
}
public synchronized void testMethodMultiSync(){
System.out.println(String.format("testMethodMultiSync:%s 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testMethodMultiSync:%s 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
线程间并行执行和没加synchronized关键字时表现一样count没按0~5顺序打印count最终值不为5
由示例2、3分析可知道,synchronized修饰非静态方法时,锁住的是当前具体实例对象
4. 静态方法上加synchronized关键字,且线程间各自有一个实例对象
private static int count = 0;
public static void main(String[] args) {
methodStaticSync();
}
public static void methodStaticSync(){
for (int i = 0; i < 5; i ++) {
SynchronizedTest test = new SynchronizedTest();
Thread thread = new Thread(() -> {
test.testMethodStaticSync();
});
thread.start();
}
}
public synchronized static void testMethodStaticSync(){
System.out.println(String.format("testMethodStaticSync:%s 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testMethodStaticSync:%s 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
count按0~5的顺序打印出来,线程间串行执行count最终为5,线程安全
由示例4中可知,就算线程间各自拥有一个实例,但线程间依然安全。因为synchronized修饰静态方法时锁住的是当前classc对象,而非具体实例对象。
5. 加在代码块中,修饰this,线程间共同一个实例对象
private static int count = 0;
public static void main(String[] args) {
codeThisSingleSync();
}
public static void codeThisSingleSync(){
SynchronizedTest test = new SynchronizedTest();
for (int i = 0; i < 5; i ++) {
Thread thread = new Thread(() -> {
test.testCodeThisSingleSync();
});
thread.start();
}
}
public void testCodeThisSingleSync(){
System.out.println(String.format("testCodeThisSingleSync:%s outer 开始 count:%s", Thread.currentThread().getName(), count));
synchronized (this){
System.out.println(String.format("testCodeThisSingleSync:%s inner 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testCodeThisSingleSync:%s inner 结束 count:%s", Thread.currentThread().getName(), count));
}
System.out.println(String.format("testCodeThisSingleSync:%s outer 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
count按0~5的顺序打印出来,代码块内线程间互斥,串行执行count最终为5,原因是count++在代码块内保证了其最终结果的正确性上图圈出绿色部分可知,synchronized代码块内串行执行,但代码块之外的还是会被其他线程穿插进来
6. 加在代码块中,修饰this,线程间各自一个实例对象
private static int count = 0;
public static void main(String[] args) {
codeThisMultiSync();
}
public static void codeThisMultiSync(){
for (int i = 0; i < 5; i ++) {
SynchronizedTest test = new SynchronizedTest();
Thread thread = new Thread(() -> {
test.testCodeThisMultiSync();
});
thread.start();
}
}
public void testCodeThisMultiSync(){
System.out.println(String.format("testCodeThisMultiSync:%s outer 开始 count:%s", Thread.currentThread().getName(), count));
synchronized (this){
System.out.println(String.format("testCodeThisMultiSync:%s inner 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testCodeThisMultiSync:%s inner 结束 count:%s", Thread.currentThread().getName(), count));
}
System.out.println(String.format("testCodeThisMultiSync:%s outer 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
count没按0~5的顺序打印出来,count最终值也不为5上图圈出绿色部分可知,synchronized代码块内的也没保证完整执行,被其他线程插入
由示例5、6可知synchronized修饰代码块中的this时,锁住的是当前实例对象
7. 加在代码块中,修饰Object
private static int count = 0;
public static void main(String[] args) {
codeObjSync1();
//codeObjSync2();
}
//1、修饰同个Object
public static void codeObjSync1(){
Object obj = new Object();
for (int i = 0; i < 5; i ++) {
SynchronizedTest test = new SynchronizedTest();
Thread thread = new Thread(() -> {
test.testCodeObjSync(obj);
});
thread.start();
}
}
//2、修饰多个object
public static void codeObjSync2(){
for (int i = 0; i < 5; i ++) {
Object obj = new Object();
SynchronizedTest test = new SynchronizedTest();
Thread thread = new Thread(() -> {
test.testCodeObjSync(obj);
});
thread.start();
}
}
public void testCodeObjSync(Object obj){
System.out.println(String.format("testCodeObjSync:%s outer 开始 count:%s", Thread.currentThread().getName(), count));
synchronized (obj){
System.out.println(String.format("testCodeObjSync:%s inner 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testCodeObjSync:%s inner 结束 count:%s", Thread.currentThread().getName(), count));
}
System.out.println(String.format("testCodeObjSync:%s outer 结束 count:%s", Thread.currentThread().getName(), count));
}
修饰同个Object运行结果如下图
修饰各自Object运行结果如下图
由示例7可知synchronized修饰代码块中的Object对象时,锁住的是当前实例对象,和this一样
8. 加在代码块中,修饰class
private static int count = 0;
public static void main(String[] args) {
codeClassSync();
}
public static void codeClassSync(){
for (int i = 0; i < 5; i ++) {
SynchronizedTest test = new SynchronizedTest();
Thread thread = new Thread(() -> {
test.testCodeClassSync();
});
thread.start();
}
}
public void testCodeClassSync(){
System.out.println(String.format("testCodeClassSync:%s outer 开始 count:%s", Thread.currentThread().getName(), count));
synchronized (SynchronizedTest.class){
System.out.println(String.format("testCodeClassSync:%s inner 开始 count:%s", Thread.currentThread().getName(), count));
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
System.out.println(String.format("testCodeClassSync:%s inner 结束 count:%s", Thread.currentThread().getName(), count));
}
System.out.println(String.format("testCodeClassSync:%s outer 结束 count:%s", Thread.currentThread().getName(), count));
}
上图运行结果分析
count按0~5的顺序打印出来,线程间串行执行count最终为5,线程安全
由示例8中可知,就算线程间各自拥有一个实例,但线程间依然安全。因为synchronized修饰代码块中的class时锁住的是当前classc对象,而非具体实例对象。