目录
用关键字synchronized声明方式时,在某些情况下是有弊端的。比如线程A调用同步方法执行一个长时间的任务,那么线程B必须等待很长的时间即A 线程执行完了才可以开始执行,这样是非常耗时的,在这种情况下就可以使用synchronized同步语句块来解决。
1.synchronized方法的弊端
创建项目t5,Task.java代码如下:
package test;
public class Task {
private String getData1;
private String getData2;
public synchronized void doLongTimeTask(){
try{
System.out.println("开始 task");
Thread.sleep(3000);
getData1 = "长时间处理任务后远程返回的值 1 threadName = "+Thread.currentThread().getName();
getData2 = "长时间处理任务后远程返回的值 2 threadName = "+Thread.currentThread().getName();
System.out.println(getData1);
System.out.println(getData2);
System.out.println("end");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
工具类CommonUtils.java:
package test;
public class CommonUtils {
public static long beginTime1;
public static long endTime1;
public static long beginTime2;
public static long endTime2;
}
线程ThreadTest1.java代码如下:
package test;
public class ThreadTest1 extends Thread{
private Task task;
public ThreadTest1(Task task){
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}
线程ThreadTest2.java代码如下:
package test;
public class ThreadTest2 extends Thread{
private Task task;
public ThreadTest2(Task task){
super();
this.task = task;
}
@Override
public void run() {
super.run();
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
}
}
运行类Run.java代码如下:
package test;
public class Run {
public static void main(String[] args) throws InterruptedException {
Task task = new Task();
ThreadTest1 threadTest1 = new ThreadTest1(task);
threadTest1.start();
ThreadTest2 threadTest2 = new ThreadTest2(task);
threadTest2.start();
try{
Thread.sleep(10000);
}catch (InterruptedException e){
e.printStackTrace();
}
long beginTime = CommonUtils.beginTime1;
if(CommonUtils.beginTime2 < CommonUtils.beginTime1){
beginTime = CommonUtils.beginTime2;
}
long endTime = CommonUtils.endTime1;
if(CommonUtils.endTime2 < CommonUtils.endTime1){
endTime = CommonUtils.endTime2;
}
System.out.println("耗时:"+ (endTime - beginTime)/1000);
}
}
运行结果如下所示:
在使用synchronized关键字俩声明方法 public synchronized void doLongTimeTask()时从运行的时间上来看,弊端很明显,解决这样的问题可以使用synchronized同步块。
2.synchronized同步代码块的使用
当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只有一个线程被执行,另一个线程必须等待当前线程完成这个代码块以后才能执行该代码块,这和synchronized同步方法是一样的。
虽然使用了synchronized同步代码块,但执行的效率还是没有提高,执行的效果还是同步运行的。
3.用同步代码块解决同步方法的弊端
创建项目t6,将上面的t5项目的代码复制下来,然后修改Task.java代码如下:
package test;
public class Task {
private String getData1;
private String getData2;
public void doLongTimeTask(){
try{
System.out.println("开始 task");
Thread.sleep(3000);
String privateGetData1 = "长时间处理任务后远程返回的值 1 threadName = "+Thread.currentThread().getName();
String privateGetData2 = "长时间处理任务后远程返回的值 2 threadName = "+Thread.currentThread().getName();
synchronized (this){
getData1 = privateGetData1;
getData2 = privateGetData2;
}
System.out.println(getData1);
System.out.println(getData2);
System.out.println("end");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
运行结果如下所示:
通过上面的实验可知,当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)同步代码块。
4.一半异步,一半同步
不在synchronized块中就是异步执行,在synchronized块中就是同步执行。
5.synchronized代码块间的同步性
在使用同步synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程同时对一个object中所有其他synchronized(this)同步代码块的访问将阻塞,这说明synchronized使用的“对象监视器”是一个。
6.验证同步synchronized(this)代码块是锁定当前对象的
和synchronized方法一样,synchronized(this)代码块也是锁定当前对象的。
以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git