synchronized 关键字代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
本文主要介绍synchronized的用法及作用域。
修饰代码块
大括号括起来的代码,作用于调用的对象
public class SyncTest {
public void test1(int j) {
synchronized (this){
for(int i = 0; i < 20; i++) {
System.out.println("test:" + j);
}
}
}
public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> syncTest1.test1(1));
executorService.execute(() -> syncTest1.test1(2));
}
}
在demo中开了两个线程调用同一个对象中的synchronized代码块,输出为先打印第一个线程的输出,在打印第二个线程的输出。
public class SyncTest {
public void test1(int j) {
synchronized (this){
for(int i = 0; i < 20; i++) {
System.out.println("test:" + j);
}
}
}
public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> syncTest1.test1(1));
executorService.execute(() -> syncTest2.test1(2));
}
}
在demo中开了两个线程调用不同实列的synchronized代码块,输出为第一个线程,第二个线程交替执行。
结论
对比可以得出synchronized修饰代码块作用域为在一个对象中
修饰方法
整个方法,作用于调用的对象
public class SyncTest {
public synchronized void test(int j) {
for (int i = 0; i < 20; i++) {
System.out.println("test:" + j);
}
}
public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> syncTest1.test(1));
executorService.execute(() -> syncTest1.test(2));
}
}
在demo中开了两个线程调用同一个对象中的synchronized修饰的方法,输出为先打印第一个线程的输出,在打印第二个线程的输出。
public class SyncTest {
public synchronized void test(int j) {
for (int i = 0; i < 20; i++) {
System.out.println("test:" + j);
}
}
public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> syncTest1.test(1));
executorService.execute(() -> syncTest2.test(2));
}
}
在demo中开了两个线程调用不同实列的synchronized修饰的方法,输出为第一个线程,第二个线程交替执行。
注意
:父类中定义了synchronized修饰的方法,由子类继承时,需要在子类显示指定synchronized修饰。synchronized不属于方法声明的一部分,不能被继承。
结论
对比可以得出,synchronized修饰的方法作用域为在一个对象中。
修饰静态方法
整个静态方法,作用于所有对象
public class SyncTest {
public void test(int j) {
print(j);
}
public static synchronized void print(int j){
for (int i = 0; i < 20; i++) {
System.out.println("test:" + j);
}
}
public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> syncTest1.test(1));
executorService.execute(() -> syncTest2.test(2));
}
}
执行demo,两个线程顺序执行,可以得出synchronized修饰的静态方法作用域为所有对象。
修饰类
括号括起来的部分,作用于所有对象
public class SyncTest {
public void test(int j) {
synchronized (SyncTest.class){
for(int i = 0; i < 10; i++) {
System.out.println("test-" + j);
}
}
}
public static void main(String[] args) {
SyncTest syncTest1 = new SyncTest();
SyncTest syncTest2 = new SyncTest();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> syncTest1.test(1));
executorService.execute(() -> syncTest2.test(2));
}
}
执行demo,两个线程顺序执行,可以得出synchronized修饰类作用域为所有对象。
总结
修饰代码块:大括号括起来的代码,作用于调用的对象。
修饰方法:整个方法,作用于调用的对象。
修饰静态方法:整个静态方法,作用于所有对象。
修饰类:括号括起来的部分,作用于所有对象。
网友评论