在高洪岩老师的《java多线程编程核心技术》一书的用同步代码块解决同步方法的弊端一节中(p76页),有这样一句话:“当一个线程访问object的一个synchronized同步代码块时,另一个线程依然可以访问该object对象中的非synchronized(this)同步代码块”。
我产生一个问题:如果线程A调用object对象中的synchronized同步代码块,线程B调用object对象中的synchronized同步代码块和非同步代码块时,如果A先占用object对象,那么B会跳过synchronized方法,而去执行后边的非同步代码块吗?
所以将书上代码略微修改一下,主要是 Task类。
package com.wang.thread.synblock;
public class Task {
private String getDate1;
private String getDate2;
public void doLongTimeTask(){
System.out.println("begin task threadName=" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
String privateGetDate1 = "长时间处理任务后从远程返回的值1 threadName=" + Thread.currentThread().getName();
String privateGetDate2 = "长时间处理任务后从远程返回的值2 threadName=" + Thread.currentThread().getName();
synchronized (this) {
System.out.println("执行同步代码块 threadName=" + Thread.currentThread().getName());
getDate1 = privateGetDate1;
getDate2 = privateGetDate2;
}
{
System.out.println("执行非同步代码块 threadName=" + Thread.currentThread().getName());
}
System.out.println(getDate1);
System.out.println(getDate2);
System.out.println("end task threadName=" + Thread.currentThread().getName());
}
public void doAsyTask(){
System.out.println("处理非同步方法 threadName=" + Thread.currentThread().getName());
}
}
MyThread1类:
package com.wang.thread.synblock;
public class MyThread1 extends Thread{
private Task task;
public MyThread1(Task task){
super();
this.task = task;
}
@Override
public void run() {
// TODO 自动生成的方法存根
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}
MyThread2类:
package com.wang.thread.synblock;
public class MyThread2 extends Thread {
private Task task;
public MyThread2(Task task){
super();
this.task = task;
}
@Override
public void run() {
// TODO 自动生成的方法存根
super.run();
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
task.doAsyTask();
}
}
Run类:
package com.wang.thread.synblock;
public class Run {
public static void main(String[] args) {
Task task = new Task();
MyThread1 thread1 = new MyThread1(task);
thread1.start();
MyThread2 thread2 = new MyThread2(task);
thread2.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
Long beginTime = CommonUtils.beginTime1;
Long endTime = CommonUtils.endTime1;
if(CommonUtils.beginTime2 < CommonUtils.beginTime1){
beginTime = CommonUtils.beginTime2;
}
if(CommonUtils.endTime2 > CommonUtils.endTime1){
endTime = CommonUtils.endTime2;
}
System.out.println("耗时:" + ((endTime - beginTime) / 1000));
}
}
结果:
begin task threadName=Thread-0
begin task threadName=Thread-1
执行同步代码块 threadName=Thread-1
执行非同步代码块 threadName=Thread-1
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
执行同步代码块 threadName=Thread-0
执行非同步代码块 threadName=Thread-0
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task threadName=Thread-0
end task threadName=Thread-1
处理非同步方法 threadName=Thread-1
耗时:3
通过结果可以看出,在B线程先占用task对象后,A线程只能等A执行完synchronized同步代码块释放锁之后,才能执行synchronized代码块,而不会跳过synchronized代码块而去执行后面的代码。
至于怎么访问对象中的非synchronized(this)代码块,我就不知道了。