java多线程基本概述(三)——同步块
1.1、synchronized方法的弊端
package commonutils; public class CommonUtils { public static long beginTime1;
public static long endTime1; public static long beginTime2;
public static long endTime2;
} =============================
package mytask; import commonutils.CommonUtils; public class Task { private String getData1;
private String getData2; public synchronized void doLongTimeTask() {
try {
System.out.println("begin 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 task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
=======================================
package mythread; import commonutils.CommonUtils; import mytask.Task; public class MyThread1 extends Thread { private Task task; public MyThread1(Task task) {
super();
this.task = task;
} @Override
public void run() {
super.run();
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
} }
=============================================
package mythread; import commonutils.CommonUtils; import mytask.Task; public class MyThread2 extends Thread { private Task task; public MyThread2(Task task) {
super();
this.task = task;
} @Override
public void run() {
super.run();
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
} }
package test; import mytask.Task;
import mythread.MyThread1;
import mythread.MyThread2; import commonutils.CommonUtils; 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) {
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));
}
}
输出结果:
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
end task
耗时:6
当把同步方法改为同步代码块时,
package mytask; import commonutils.CommonUtils; public class Task { private String getData1;
private String getData2; public void doLongTimeTask() {
synchronized(Task.class){
try {
System.out.println("begin 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 task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
}
输出结果:
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
end task
耗时:6
可见,并没有提升效率,这是因为锁定的范围比较广,所以效果和锁方法的差别并不是太。那么可以缩小边界区,也就是资源真正开始竞争的地方。因为类中的成员变量才是资源的竞争对象,所以需要在访问这些变量的地方进行锁定。那么代码改为如下:
package mytask; import commonutils.CommonUtils; public class Task { private String getData1;
private String getData2; public void doLongTimeTask() { try {
System.out.println("begin task");
Thread.sleep(3000);
getData1 = "长时间处理任务后从远程返回的值1 threadName="
+ Thread.currentThread().getName();
getData2 = "长时间处理任务后从远程返回的值2 threadName="
+ Thread.currentThread().getName();
synchronized(Task.class){
System.out.println(getData1);
System.out.println(getData2);
}
System.out.println("end task");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
输出结果:
begin task
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值2 threadName=Thread-1
end task
耗时:3
这时候可以看到时间已经减小了,这就出现一部分同步,一部分异步了。如何验证是真的一半同步一半异步呢?
package mytask; public class Task { public void doLongTimeTask() {
for (int i = 0; i < 100; i++) {
System.out.println("nosynchronized threadName="
+ Thread.currentThread().getName() + " i=" + (i + 1));
}
System.out.println("");
synchronized (this) {
for (int i = 0; i < 100; i++) {
System.out.println("synchronized threadName="
+ Thread.currentThread().getName() + " i=" + (i + 1));
}
} }
}
输出结果:
=================================非同步块异步执行
nosynchronized threadName=Thread-0 i=1
nosynchronized threadName=Thread-1 i=1
nosynchronized threadName=Thread-0 i=2
nosynchronized threadName=Thread-1 i=2
nosynchronized threadName=Thread-0 i=3
nosynchronized threadName=Thread-1 i=3
nosynchronized threadName=Thread-0 i=4
nosynchronized threadName=Thread-1 i=4
nosynchronized threadName=Thread-0 i=5
nosynchronized threadName=Thread-1 i=5
nosynchronized threadName=Thread-0 i=6
nosynchronized threadName=Thread-1 i=6
nosynchronized threadName=Thread-0 i=7
nosynchronized threadName=Thread-1 i=7
nosynchronized threadName=Thread-0 i=8
nosynchronized threadName=Thread-1 i=8
=================================同步块同步执行
synchronized threadName=Thread-1 i=85
synchronized threadName=Thread-1 i=86
synchronized threadName=Thread-1 i=87
synchronized threadName=Thread-1 i=88
synchronized threadName=Thread-1 i=89
synchronized threadName=Thread-1 i=90
synchronized threadName=Thread-1 i=91
synchronized threadName=Thread-1 i=92
synchronized threadName=Thread-1 i=93
synchronized threadName=Thread-1 i=94
synchronized threadName=Thread-1 i=95
synchronized threadName=Thread-1 i=96
synchronized threadName=Thread-1 i=97
synchronized threadName=Thread-1 i=98
synchronized threadName=Thread-1 i=99
synchronized threadName=Thread-1 i=100
synchronized threadName=Thread-0 i=1
synchronized threadName=Thread-0 i=2
synchronized threadName=Thread-0 i=3
synchronized threadName=Thread-0 i=4
synchronized threadName=Thread-0 i=5
synchronized threadName=Thread-0 i=6
synchronized threadName=Thread-0 i=7
synchronized threadName=Thread-0 i=8
synchronized threadName=Thread-0 i=9
synchronized threadName=Thread-0 i=10
synchronized threadName=Thread-0 i=11
synchronized threadName=Thread-0 i=12
synchronized threadName=Thread-0 i=13
synchronized threadName=Thread-0 i=14
synchronized threadName=Thread-0 i=15
synchronized threadName=Thread-0 i=16
java多线程基本概述(三)——同步块的更多相关文章
- java多线程中的三种特性
java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...
- Java多线程学习(三)volatile关键字
转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79680693 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...
- Java多线程——线程之间的同步
Java多线程——线程之间的同步 摘要:本文主要学习多线程之间是如何同步的,如何使用volatile关键字,如何使用synchronized修饰的同步代码块和同步方法解决线程安全问题. 部分内容来自以 ...
- Java多线程之线程的同步
Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...
- 如何实现有返回值的多线程 JAVA多线程实现的三种方式
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口.执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable ...
- Java 多线程基础(三) start() 和 run()
Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...
- java多线程二之线程同步的三种方法
java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Se ...
- java 多线程: Thread 并发访问-代码块同步synchronized {};String作为被锁的对象
方法同步的弊端 方法同步的时候,如果一个方法需要线程安全控制的代码速度其实很快,但是还有其他的业务逻辑代码耗时非常长(比如网络请求),这样所有的线程就在这一块就等待着了,这样造成了极大的资源浪费如果并 ...
- java多线程基本概述(三)——同步方法
非线程安全其实是在多个线程对同一个对象实例的变量进行并发访问的时候发生,产生的后果就是脏读,也就是取到的数据是修改过的.而线程安全就是获得的实例变量的值是经过同步处理的,从而不会出现脏读现象. 1.1 ...
随机推荐
- vuejs数据双向绑定原理(get & set)
前端的数据双向绑定指的是view(视图)和model(数据)两者之间的关系:view层是页面上展示给用户看的信息,model层一般是指通过http请求从后台返回的数据.view到model的绑定都是通 ...
- li点击弹出序号
<body> <ul> <li>test1</li> <li>test2</li> <li>test3</li ...
- [vijosP1303]导弹拦截(最长上升子序列转LCS)
描述 某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭 ...
- Scrapy 初体验
开发笔记 Scrapy 初体验 scrapy startproject project_name 创建工程 scrapy genspider -t basic spider_name website. ...
- wemall app商城源码中实现带图片和checkbox的listview
wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享其中实现带图片和checkbox的listvi ...
- wemall app商城源码中基于PHP的ThinkPHP惯例配置文件代码
wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...
- 1059: [ZJOI2007]矩阵游戏
1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2154 Solved: 1053[Submit][Stat ...
- 网络AFNetworking 3.1
下面的类已从AFNetworking 3.0中废弃: AFURLConnectionOperation AFHTTPRequestOperation AFHTTPRequestOperationMan ...
- Solr DateRangeField
Solr DateRangeField 是solr5.0 实现的一个feature. 关于 DateRangeField 支持日期查询如 date_field:[2016-03-23 TO 2017 ...
- js数据类型:引用和5种基本数据类型
javascript有2种基本数据类型:引用和基本数据类型 基本数据类型又有5个分类:布尔型.字符串.数值.undefined.NULL.