2.2synchronized同步语句块
使用synchronized虽然能够避免不同步的现象出现,但是也会出现弊端,比如代码执行时间过长,那么其他线程就必须等待该线程执行完毕释放锁之后才能拿到锁。
面对这种问题可以使用同步代码块来解决。
2.2.1synchronized方法的弊端:
任务类:
public class Task {
private String getData1;
private String getData2;
synchronized public void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep();
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) {
e.printStackTrace();
}
}
}
工具类:
public class CommonUtils {
public static long beginTime1;
public static long endTime1;
public static long beginTime2;
public static long endTime2;
}
线程代码1:
public class Thread1 extends Thread {
private Task task;
public Thread1(Task task) {
this.task = task;
} @Override
public void run() {
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}
线程代码2:
public class Thread2 extends Thread {
private Task task;
public Thread2(Task task) {
this.task = task;
} @Override
public void run() {
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
}
}
执行代码:
public class Main {
public static void main(String[] args) {
Task task = new Task();
Thread1 thread1 = new Thread1(task);
thread1.start();
Thread2 thread2 = new Thread2(task);
thread2.start();
try {
Thread.sleep();
} 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) / ); }
}
执行结果:
从结果看这样运行一段代码耗时严重,解决这样的问题可以使用synchronized同步代码块。
2.2.2synchronized同步代码块的使用:
两个线程同时访问同一个对象的synchronized(this)同步代码块时,在代码运行期间只能有一个线程执行该段代码块,另一个线程必须等待当前线程完成执行才能够执行该段代码。
模块业务类:
public class ObjectService {
public void serviceMethod() {
try {
synchronized (this) {
System.out.println("begin time = " + System.currentTimeMillis());
Thread.sleep(2000);
System.out.println("end time = " + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程代码1:
public class Thread3 extends Thread {
private ObjectService objectService;
public Thread3(ObjectService objectService) {
this.objectService = objectService;
} @Override
public void run() {
objectService.serviceMethod();
}
}
线程代码2:
public class Thread4 extends Thread {
private ObjectService objectService;
public Thread4(ObjectService objectService) {
this.objectService = objectService;
} @Override
public void run() {
objectService.serviceMethod();
}
}
执行代码:
public class Main {
public static void main(String[] args) {
ObjectService objectService = new ObjectService();
Thread3 thread3 = new Thread3(objectService);
thread3.setName("a");
thread3.start();
Thread4 thread4 = new Thread4(objectService);
thread4.setName("b");
thread4.start();
}
}
执行结果:
这样使用同步代码块,并没有使代码的效率提高,执行的效果还是同步执行的。下面的示例中解决synchronized同步代码块执行效率低的问题。
2.2.3用同步代码块解决同步方法的弊端:
任务类:
public class DoLongTimeTask1 {
private String getData1;
private String getData2;
public void doLongTimeTask() {
try {
System.out.println("begin task");
Thread.sleep(3000);
String privateData1 = "长时间处理任务后从后台远程返回的值1 threadName = "
+ Thread.currentThread().getName();
String privateData2 = "长时间处理任务后从后台远程返回的值2 threadName = "
+ Thread.currentThread().getName();
synchronized (this) {
getData1 = privateData1;
getData2 = privateData2;
}
System.out.println(getData1);
System.out.println(getData2);
System.out.println("end task");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程代码1:
public class Thread1 extends Thread {
private Task task;
public Thread1(Task task) {
this.task = task;
} @Override
public void run() {
CommonUtils.beginTime1 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime1 = System.currentTimeMillis();
}
}
线程代码2:
public class Thread2 extends Thread {
private Task task;
public Thread2(Task task) {
this.task = task;
} @Override
public void run() {
CommonUtils.beginTime2 = System.currentTimeMillis();
task.doLongTimeTask();
CommonUtils.endTime2 = System.currentTimeMillis();
}
}
执行代码:
public class Main {
public static void main(String[] args) {
Task task = new Task();
Thread1 thread1 = new Thread1(task);
thread1.start();
Thread2 thread2 = new Thread2(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); }
}
执行结果:
从上述可知当一个线程访问object中的synchronized同步代码块时,其他线程可以访问该object对象中非synchronized(this)同步代码块的内容。
时间缩短,且运行效率加快,而且能够保持synchronized是同步的且当前线程持有锁。下面的示例进行验证。
2.2.4一半异步,一半同步:
事先说明:不在synchronized块中的代码使异步的,在synchronized中的代码是同步的。
任务代码:
public class Task1 {
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));
}
}
}
}
线程代码1:
public class Task1 {
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));
}
}
}
}
线程代码2:
public class Thread6 extends Thread {
private Task1 task;
public Thread6(Task1 task) {
this.task = task;
} @Override
public void run() {
task.doLongTimeTask();
}
}
执行代码:
public class Main {
public static void main(String[] args) {
Task1 task = new Task1();
Thread5 thread5 = new Thread5(task);
thread5.start();
Thread6 thread6 = new Thread6(task);
thread6.start(); }
}
执行结果(左边为非同步,右边为同步):
可以看出在同步代码块中的代码是同步运行的,而在非同步代码块中的代码是异步运行的。
2.2.5synchronized代码块间的同步性:
若一个线程访问了object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有的其他synchronized(this)同步代码块的访问将被阻塞。
这个现象表明了:synchronized使用的是一个对象监视器。
注:产生了疑惑,是否同步代码块与同步方法是同步的,然后做了测试发现同步代码块与同步方法之间是同步。(仅需要在同步代码块中调用同步方法,然后开启多条线程即可)(具体代码在fifthTask2与Thread7中)。
也就是说说,对象监视器针对的是synchronized这个关键字。
业务代码:
public class ObjectService1 {
public void serviceMethodA() {
try {
synchronized (this) {
System.out.println("A begin time = " +System.currentTimeMillis() );
System.out.println("A end time = " + System.currentTimeMillis());
Thread.sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} public void serviceMethodB() {
synchronized (this) {
System.out.println("B begin time = " +System.currentTimeMillis() );
System.out.println("B end time = " + System.currentTimeMillis());
}
}
}
线程代码1:
public class Thread8 extends Thread {
private ObjectService1 objectService1; public Thread8(ObjectService1 objectService1) {
this.objectService1 = objectService1;
} @Override
public void run() {
objectService1.serviceMethodA();
}
}
线程代码2:
public class Thread9 extends Thread {
private ObjectService1 objectService1; public Thread9(ObjectService1 objectService1) {
this.objectService1 = objectService1;
} @Override
public void run() {
objectService1.serviceMethodB();
}
}
执行代码:
public class Main {
public static void main(String[] args) {
ObjectService1 service = new ObjectService1();
Thread8 a = new Thread8(service);
a.setName("a");
a.start();
Thread9 b = new Thread9(service);
b.setName("b");
b.start();
}
}
执行结果:
可以看到不同的synchronized是存在同步关系的,即当一个线程获得锁后,对该对象的所有synchronized修饰的临界区都具有锁的效应。
2.2.6验证同步synchronized(this)代码块时锁定当前对象的:
synchronized修饰代码块时与synchronized修饰方法时是一样的都是锁定当前对象(对当前对象加锁)。
任务代码:
public class Task {
public void method() {
System.out.println("--------------run--method");
} public void doLongTimeTask() {
synchronized (this) {
for (int i = ; i < ; i++) {
System.out.println("synchronized threadName = " +
Thread.currentThread().getName() + " i = " + (i + ));
}
}
}
}
线程代码1:
public class Thread10 extends Thread {
private Task task;
public Thread10(Task task) {
this.task = task;
} @Override
public void run() {
task.doLongTimeTask();
}
}
线程代码2:
public class Thread11 extends Thread {
private Task task;
public Thread11(Task task) {
this.task = task;
} @Override
public void run() {
task.method();
}
}
执行代码:
public class Main {
public static void main(String[] args) throws Exception{
Task task = new Task();
Thread10 thread10 = new Thread10(task);
thread10.start();
Thread.sleep(10);
Thread11 thread11 = new Thread11(task);
thread11.start();
}
}
执行结果:
修改任务代码:
public class Task {
synchronized public void method() {
System.out.println("--------------run--method");
} public void doLongTimeTask() {
synchronized (this) {
for (int i = 0; i < 100000; i++) {
System.out.println("synchronized threadName = " +
Thread.currentThread().getName() + " i = " + (i + 1));
}
}
}
}
执行结果:
2.2.7将任意对象作为对象监视器:
多个线程调用同一个对象的synchronized同步方法或者synchronized(this)同步代码块时,调用的方法时按顺序执行的,是同步的是阻塞的。
说明synchronized同步方法与synchronized(this)同步代码块有两种作用。
synchronized同步方法
- 对其他synchronized同步方法或synchronized(this)同步代码块调用起阻塞作用。
- 同一时间只有一个线程可以执行synchronized修饰的隔离区中的代码
synchronized(this)同步代码块
- 对其他synchronized同步方法或synchronized(this)同步代码块调用起阻塞作用。
- 同一时间只有一个线程可以执行synchronized修饰的隔离区中的代码
在前面的学习中,使用synchronized(this)格式来同步代码块,其实java还支持对“任意对象”作为“对象监视器”来实现同步功能,这个“任意对象”大多数是实例变量及方法的参数,使用格式为synchronized(非this对象)。
synchronized(非this对象)格式的作用只有1种,synchronized(非this对象X)同步代码块。
在多个线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象X)同步代码块中的代码。
当持有对象监视器为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象X)同步代码块中的代码。
用户业务代码:
public class UserService {
private String usernameParam;
private String passwordParam;
private String anyString = new String();
public void setUsernamePassword(String username, String password) {
try {
synchronized (anyString) {
System.out.println("线程名称为: " + Thread.currentThread().getName() +
" 在 "+ System.currentTimeMillis() + " 进入同步代码块");
usernameParam = username;
Thread.sleep(1000);
passwordParam = password;
System.out.println("线程名称为: " + Thread.currentThread().getName() +
" 在 " +System.currentTimeMillis() + " 离开同步代码块");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程代码1:
public class Thread12 extends Thread {
private UserService service;
public Thread12(UserService service) {
this.service = service;
} @Override
public void run() {
service.setUsernamePassword("a","aa");
}
}
线程代码2:
public class Thread13 extends Thread {
private UserService service;
public Thread13(UserService service) {
this.service = service;
} @Override
public void run() {
service.setUsernamePassword("b","bb");
}
}
执行代码:
public class Main {
public static void main(String[] args) throws Exception{
UserService service = new UserService();
Thread12 a = new Thread12(service);
a.setName("A");
a.start();
Thread13 b = new Thread13(service);
b.setName("B");
b.start();
}
}
执行结果:
锁定非this对象具有的优点:如果在一个类中有很多个synchronized方法,这时虽然能实现同步,但会受阻,所以影响效率;但如果使用同步代码块锁非this对象,则synchronized(非this)daima
2.2synchronized同步语句块的更多相关文章
- java synchronized静态同步方法与非静态同步方法,同步语句块
摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...
- synchronized同步语句块
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长时间.在这样的情况下可以使用synchronized同步语句块来解 ...
- java多线程(三)——锁机制synchronized(同步语句块)
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解 ...
- 2.2.2synchronized同步代码块的使用
当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程执行,另一个线程必须等待期执行完才能执行. package com.cky.bea ...
- 对象及变量的并发访问(同步方法、同步代码块、对class进行加锁、线程死锁)&内部类的基本用法
主要学习多线程的并发访问,也就是使得线程安全. 同步的单词为synchronized,异步的单词为asynchronized 同步主要就是通过锁的方式实现,一种就是隐式锁,另一种是显示锁Lock,本节 ...
- 同步方法、同步代码块、volidate变量的使用
当多个线程涉及到共享数据的时候,就会设计到线程安全的问题.非线程安全其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”.发生脏读,就是取到的数据已经被其他的线程改过了. ...
- java中的synchronized同步代码块和同步方法的区别
下面这两段代码有什么区别? //下列两个方法有什么区别 public synchronized void method1(){} public void method2(){ synchronized ...
- 线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步
假设多个线程共享一个静态变量,如果让每个线程都执行相同的方法每次让静态变量自增1,这样的做法线程安全吗?能保证自增变量数据同步吗?本篇体验使用lock语句块和Interlocked类型方法保证自增变量 ...
- Java基础之线程——管理线程同步代码块(BankOperation4)
控制台程序. 除了同步类对象的方法之外,还可以把程序中的语句或代码块制定为synchronized,这种方式更强大,因为可以指定哪个对象从语句或代码块的同步中获益,而不像同步方法那样仅仅是包含代码的对 ...
随机推荐
- 《Java线程池》:任务拒绝策略
在没有分析线程池原理之前先来分析下为什么有任务拒绝的情况发生. 这里先假设一个前提:线程池有一个任务队列,用于缓存所有待处理的任务,正在处理的任务将从任务队列中移除.因此在任务队列长度有限的情况下就会 ...
- jvm的字符串池
1 jvm中是有专门的字符串池的内存空间的,这块空间和栈和堆不同. 2 String s = "string constant"; 这个时候,如果string pool中没有&qu ...
- Android获取系统外置存储卡路径的方法
android系统可通过Environment.getExternalStorageDirectory()获取存储卡的路径.可是如今有非常多手机内置有一个存储空间.同一时候还支持外置sd卡插入,这样通 ...
- 12.Django数据库操作(执行原生SQL)
1.使用extra方法 解释:结果集修改器,一种提供额外查询参数的机制 说明:依赖model模型 用在where后: Book.objects.filter(publisher_id="1& ...
- jQuery:[1]实现图片上传并预览
jQuery:[1]实现图片上传并预览 原理 预览思路 1.当上传对象的input被触发并选择本地图片之后获取要上传的图片对象的URL: 2.把对象URL赋值给实现写好的img标签的src属性 Fil ...
- ubuntu14.04搭建gitlab
以下内容来自:https://mirror.tuna.tsinghua.edu.cn/help/gitlab-ce/ (清华大学开源软件镜像站)可以直接移步上面的网站.这里做个笔记,也是为了记录一下 ...
- ubuntu中文语言环境下把系统中文文件夹更改回英文文件夹
更改系统语言为“汉语(中国)”后,在主文件夹下的系统默认文件夹名称也被改成了中文, 这样的话,使用命令行终端进行入文件夹很不方便,所以可以把文件夹名称从中文改回英文. 打开终端,在终端中输入命令:ex ...
- P2163 [SHOI2007]园丁的烦恼
题目 P2163 [SHOI2007]园丁的烦恼 做法 关于拆点,要真想拆直接全部用树状数组水过不就好了 做这题我们练一下\(cdq\)分治 左下角\((x1,y1)\)右上角\((x2,y2)\), ...
- shell 批量创建_备份 mysql 数据库 表
#!/bin/bash user=root password= socket=/var/lib/mysql/mysql.sock mycmd="mysql -u$user -p$passwo ...
- 在webBrowser中取Cookie的方法
在很多情况下我们会使用间进程的webBrowser去实现一些网页的请求和抓去,这个时候有部分网页是取不到Cookie的,那怎么办呢?下面我提供一个方法,应该99%的都能取到, //取当前webBrow ...