测试Synchronized在多线程情况下的实现
首先,Synchronized修饰的对象有四种
1.修饰一个代码块
2.修饰一个静态方法
3.修饰一个实例方法
4.修饰一个类
1.用相同对象修饰代码块/方法输出测试
尝试用两次调用代码块
注:调用线程池来创建线程,因为如果不调用线程池的话,类的同一个对象ex两次调用同一个方法本身就是同步执行没法看出锁的情况。线程池创建两个线程执行代码块。
public class SynchronizedEx1 {
// 修饰方法里的代码块
public void test() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println("test current is " +i);
}
}
}
public static void main(String[] args) {
SynchronizedEx1 ex = new SynchronizedEx1();
//用线程池
ExecutorService exService = Executors.newCachedThreadPool();
//开启一个线程执行方法
exService.execute(() -> {
ex.test();
});
exService.execute(() -> {
ex.test();
});
}
}
由以上代码可看出,首先是执行了一遍完整的test作用的对象是调用了代码块的对象
2.用不同对象修饰代码块/方法输出测试
public class SynchronizedEx2 {
// 修饰一个方法,用n来标识具体作用的对象
public synchronized void test2(int n) {
for (int i = 0; i < 6; i++) {
System.out.println("test"+n+"is"+i );
}
}
public static void main(String[] args) {
SynchronizedEx2 ex1 = new SynchronizedEx2();
SynchronizedEx2 ex2 = new SynchronizedEx2();
ExecutorService exService = Executors.newCachedThreadPool();
exService.execute(() -> {
ex1.test2(1);
});
executorService.execute(() -> {
ex2.test2(2);
});
}
}
由结果可看出,不同的对象各自的调用是互相不影响的。
3.用不同对象修饰类的输出测试
同一个对象调用类方法和不同对象调用类方法的执行结果一样,这里直接给出不同对象情况的代码:
public class SynchronizedEx3 {
//用反射达到修饰类并调用执行的目的
public static void test(int j) {
synchronized (SynchronizedEx3.class) {
for (int i = 0; i < 6; i++) {
System.out.println("test"+n+"is"+i );
}
}
}
public static void main(String[] args) {
SynchronizedEx3 ex1 = new SynchronizedEx3();
SynchronizedEx3 ex2 = new SynchronizedEx3();
ExecutorService exService = Executors.newCachedThreadPool();
exService.execute(() -> {
ex.test(1);
});
executorService.execute(() -> {
ex.test(2);
});
}
}
执行结果是先ex1执行完后再执行ex2,可见Synchronized修饰类时是作用于所有对象的:
Synchronized修饰类和静态代码块一样,同一时间只有一个线程可以执行。
注:Synchronize在修饰对类,方法时并不属于可继承的特性,子类/重写方法是不会自动带有Synchronized同步性的