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 ...
随机推荐
- wap问答系统工作总结
一直想找个锻炼自己的机会,但是又很恐慌,怕自己能力太差,把握不住机会,把事情弄糟. 终于,要做wap问答系统了,本来说是几个人一块儿做,我分析了下页面,发现共同的部分还是比较多的,有点想法,要不我接过 ...
- Java的容器类小结
Java的容器类其实就是集合类,只是为了不与Collection接口混淆,国内基本翻译为容器类. 容器类分为两种:独立元素序列的Collection和键值对的Map. Collection主要有如下几 ...
- Selenium 上传文件失败,解决办法一
昨个改程序遇到一个问题,UI上面有需要上传文件的地方.但是我不知道怎么让Selenium完成 点击上传文件按钮->在弹出的文件选择窗口中选择路径和文件,点确定. 要知道弹出窗口属于window的 ...
- wemall app商城源码机器人检测
wemall-mobile是基于WeMall的Android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享wemall app商城源码Android之 ...
- 【iOS】7.4 定位服务->2.1.2 定位 - 官方框架CoreLocation: CLLocationManager(位置管理器)
本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正. 本文相关目录: ================== 所属文集:[iOS]07 设备工具 === ...
- php数组的使用
<?php echo "<h2>--------普通数组--------</h2>"; $arr1 = array(1,2,3,4); print_r ...
- CSS后代选择器、子元素选择器、相邻兄弟选择器区别与详解
派生选择器用的很多,派生选择器具体包括为后代选择器.子元素选择器.相邻兄弟选择器,我们来理解一下他们之间的具体用法与区别. 1.css后代选择器语法:h1 em {color:red;} 表示的是从h ...
- 读learning spark lighting chapter1~chapter2
chapter 1 introduction to the analysis with spark the conponents of Sparks spark core(contains the b ...
- 百度推出 MIP Shell 链接
在站长将站点 MIP 化时,需要关注 URL 的一共有三个:MIP URL, MIP-Cache URL 以及 MIP-Shell URL. 从 URL 说起 在互联网中,URL 定义页面的地址,每个 ...
- Android开发之NavigationView的使用
NavigationView主要是和DrawerLayout框架结合使用,来完成抽屉导航实现侧边栏 引用一段官方文档的示例代码 <android.support.v4.widget.Drawer ...