synchronized复杂实例
第一类:对象锁实例
1.1同一实例的对象锁
对一个实例(对象)的异步方法、同步方法、同步陈述 访问实例
实例类代码
//异步、同步实例函数、同步对象(this)Statement陈述
public class SyncThread implements Runnable{
@Override
public void run() {
//currentThread():Returns a reference to the currently executing thread object
//getName():Returns this thread's name
//对传入线程进行名称判断,分别执行不同的函数
//(异步实例函数、同步实例函数,异步实例函数中的同步陈述)
String threadName = Thread.currentThread().getName();
if (threadName.startsWith("A")){
try {
async();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if (threadName.startsWith("B")){
try {
syncStatemnet();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if (threadName.startsWith("C")){
try {
syncInstance();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 异步实例函数:多个线程可同时访问类非同步(异步)函数async()
* @throws InterruptedException
*/
private void async() throws InterruptedException {
//打印,线程名+开始(格式化后的时间)
System.out.pr1intln(Thread.currentThread().getName()+"_Async_Start:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(2000);
//打印,线程名+结束(格式化后的时间)
System.out.println(Thread.currentThread().getName()+"_Async_End:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
/**
* 同步实例函数:每个线程执行此函数需要线获取对象锁,才能执行,否则阻塞(等待/挂起)
* @throws InterruptedException
*/
private synchronized void syncInstance() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"_SyncInstance_Start:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"_SyncInstance_End:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
/**
* 异步函数中的同步陈述:这个函数还是异步的,但里面有同步陈述
* 所有线程都可先访问进入这个函数,但执行到同步陈述时,需要先获取对象锁,否则阻塞
* @throws InterruptedException
*/
private void syncStatemnet() throws InterruptedException {
//异步实例函数中的非同步Statement
System.out.println(Thread.currentThread().getName() + "_SyncStatemnet()_HasIn:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
//异步实例函数中的同步Statement
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "_SyncStatemnet_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "_SyncStatemnet_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
}
测试类主函数代码
public class SyncTest {
public static void main(String[] args) {
SyncThread syncThread = new SyncThread();
//A 普通实例函数,异步【可被多个线程同时访问】
Thread A_thread1 = new Thread(syncThread, "A_thread1");
Thread A_thread2 = new Thread(syncThread, "A_thread2");
//B 修饰陈述Statement,同步【同步Statement会被线程独占】
Thread B_thread1 = new Thread(syncThread, "B_thread1");
Thread B_thread2 = new Thread(syncThread, "B_thread2");
//C 修饰实例函数,同步【同步实例函数会被线程独占】
Thread C_thread1 = new Thread(syncThread, "C_thread1");
Thread C_thread2 = new Thread(syncThread, "C_thread2");
A_thread1.start();
A_thread2.start();
B_thread1.start();
B_thread2.start();
C_thread1.start();
C_thread2.start();
}
结果解析
双击可放大
结果分析1:
同一个对象的两个线程,访问异步函数,是同时执行的
同一个对象的两个线程,访问同步实例函数,是不能同时进行的,需要等待上一个线程完成,下一个线程才能执行
同一个对象的两个线程,访问同步陈述,是不能同时进行的,但非同步陈述的语句仍是异步语句,是同时执行的
1.2不同实例的对象锁
对不同实例(对象),访问各自的异步方法、同步方法陈述实例
实例类代码
同1.1实例类代码
测试类主函数代码
修改1.1测试类代码
public class SyncTest {
public static void main(String... args) {
//删除 SyncThread syncThread = new SyncThread();
//为每一个线程都new一个不同的SyncThread对象。
Thread A_thread1 = new Thread(new SyncThread(), "A_thread1");
Thread A_thread2 = new Thread(new SyncThread(), "A_thread2");
Thread B_thread1 = new Thread(new SyncThread(), "B_thread1");
Thread B_thread2 = new Thread(new SyncThread(), "B_thread2");
Thread C_thread1 = new Thread(new SyncThread(), "C_thread1");
Thread C_thread2 = new Thread(new SyncThread(), "C_thread2");
A_thread1.start();
A_thread2.start();
B_thread1.start();
B_thread2.start();
C_thread1.start();
C_thread2.start();
}
}
结果解析
//console
A_thread1_Async_Start:23:55:37
C_thread2_SyncInstance_Start:23:55:37
B_thread2_SyncStatemnet()_HasIn:23:55:37
A_thread2_Async_Start:23:55:37
C_thread1_SyncInstance_Start:23:55:37
B_thread1_SyncStatemnet()_HasIn:23:55:37
B_thread2_SyncStatemnet_Start:23:55:37
B_thread1_SyncStatemnet_Start:23:55:37
A_thread1_Async_End:23:55:39
C_thread2_SyncInstance_End:23:55:39
A_thread2_Async_End:23:55:39
C_thread1_SyncInstance_End:23:55:39
B_thread2_SyncStatemnet_End:23:55:39
B_thread1_SyncStatemnet_End:23:55:39
结果分析2:
两个线程访问不同对象的 synchronized(this|object) {} 代码块和 synchronized 修饰非静态方法是异步的,因为对象锁是针对一个对象而言的,多个对象的对象锁是相互独立存在。
同一个类的不同对象(实例)的对象锁互不干扰,相互独立。
第二类:类锁实例
2.1同一实例的类锁
实例类代码
修改SyncThread类的同步实例方法为同步静态(类)方法
及修改同步Statement this为SyncThread.class
以下仅给出修改部分的代码
//同步实例方法改为同步静态(类)方法
//加static修饰符
private synchronized static void syncInstance() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"_SyncInstance_Start:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"_SyncInstance_End:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
//this改为SyncThread.class
private void syncStatemnet() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + "_SyncStatemnet()_HasIn:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
//原this改为SyncThread.class
synchronized (SyncThread.class) {
System.out.println(Thread.currentThread().getName() + "_SyncStatemnet_Start:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + "_SyncStatemnet_End:" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
}
}
测试类主函数代码
同1.1同一实例的对象锁 的 测试类主函数代码
结果解析
//console
B_thread2_SyncStatemnet()_HasIn:00:38:59
C_thread2_SyncInstance_Start:00:38:59
B_thread1_SyncStatemnet()_HasIn:00:38:59
A_thread2_Async_Start:00:38:59
A_thread1_Async_Start:00:38:59
A_thread2_Async_End:00:39:01
C_thread2_SyncInstance_End:00:39:01
B_thread1_SyncStatemnet_Start:00:39:01
A_thread1_Async_End:00:39:01
B_thread1_SyncStatemnet_End:00:39:03
B_thread2_SyncStatemnet_Start:00:39:03
B_thread2_SyncStatemnet_End:00:39:05
C_thread1_SyncInstance_Start:00:39:05
C_thread1_SyncInstance_End:00:39:07
结果分析:
异步方法(B_thread1&2_SyncStatemnet()_HasIn,A_thread1&2_Async_Start)同时开始
虽然A1,A2,B1,B2是同时开始(当然B1,B2开始的是异步语句,还有同步陈述没有运行)但A1,A2在2s后同时结束,而全部的类方法及类陈述需要一个一个排队执行。
同步静态(类)方法C2(Start:00:38:59)先开始,2s后C2(End:00:39:01)结束
然后静态陈述B1(Start:00:39:01)再开始,2s后B1(End:00:39:03)结束
然后静态陈述B2(Start:00:39:03)再开始,2s后B2(End:00:39:05)结束
然后静态(类)方法C1(Start:00:39:05)再开始,2s后C1(End:00:39:07)结束
一个停车场出口,4辆车排队交费出去。共耗费了38:59-39:07,8s时间
也就是,同一实例的类方法与获取.class的类陈述都是排一个队来执行自己的代码。
与对象锁的,同一实例的实例方法与获取this的实例陈述是一样的。
2.2不同实例的类锁
实例类代码
同上2.1同一实例的类锁的实例类代码
测试类主函数代码
同1.2不同实例的对象锁的测试类主函数代码
结果解析
测试结果:
//console
A_thread1_Async_Start:00:42:31
B_thread2_SyncStatemnet()_HasIn:00:42:31
C_thread1_SyncInstance_Start:00:42:31
B_thread1_SyncStatemnet()_HasIn:00:42:31
A_thread2_Async_Start:00:42:31
A_thread1_Async_End:00:42:33
C_thread1_SyncInstance_End:00:42:33
B_thread1_SyncStatemnet_Start:00:42:33
A_thread2_Async_End:00:42:33
B_thread1_SyncStatemnet_End:00:42:35
B_thread2_SyncStatemnet_Start:00:42:35
B_thread2_SyncStatemnet_End:00:42:37
C_thread2_SyncInstance_Start:00:42:37
C_thread2_SyncInstance_End:00:42:39
结果分析:
两个线程访问不同对象的 synchronized(类.class)陈述 {} 或 synchronized 修饰静态方法还是同步的。对于同一个类的不同对象的类锁是同一个,类锁是类不同对象共享的。
第三类:类锁对象锁均有
一个类同时有对象锁(this/实例方法)类锁(.class/静态方法)
同一类同一对象
同一对象会有怎样影响?
结论
一个类,可以同时拥有 synchronized 修饰的实例方法(对象锁)、静态方法(类锁)。
这两个同步方法(类/对象锁)通过 同一个对象的不同线程 是 可以同时执行/访问的。
同一类不同对象
两个对象会有怎样影响?
结论
同一类的两个对象的对象锁方法同时执行,同一类的两个对象的类锁方法排队执行。
总结
对象锁 与 类锁相互独立,工作性质相同,只是管辖范围不同。
对象锁一个是管实例函数及实例陈述,类锁管类函数及类陈述。