java多线程(三)——锁机制synchronized(同步语句块)
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解决。
一、用同步代码块解决同步方法的弊端
Task类
package com.weishiyao.learn.day4.testSynchorized.ep2;
public class Task {
private String getData1;
private String getData2;
public void doLongTimeTask() {
try {
System.out.println("begin 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 task");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
常量工具类
package com.weishiyao.learn.day4.testSynchorized.ep2;
public class CommonUtils {
public static long beginTime1;
public static long endTime1;
public static long beginTime2;
public static long endTime2;
}
线程类——2个
package com.weishiyao.learn.day4.testSynchorized.ep2;
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 com.weishiyao.learn.day4.testSynchorized.ep2;
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 com.weishiyao.learn.day4.testSynchorized.ep2;
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
begin task
长时间处理任务后从远程返回的值1 threadName=Thread-1
长时间处理任务后从远程返回的值1 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
长时间处理任务后从远程返回的值2 threadName=Thread-0
end task
end task
耗时3 秒
这里是用的synchronized代码锁,如果换成方法锁
所有代码不变,仅更改Task类
package com.weishiyao.learn.day4.testSynchorized.ep2;
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();
}
}
}
运行结果
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 秒
可以得出结论,当一个线程访问object的synchronized同步代码块时,另一个线程依然可以访问非同步代码块,这样同步代码块就会比同步方法所花费更短的时间,可以得到更高的效率,在同步代码块中代码是同步的,不在同步代码块中代码是异步的。
二、synchronized代码块间的同步性
当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,因为synchronized使用的是一个“对象监视器”
ObjectService类
package com.weishiyao.learn.day4.testSynchorized.ep3;
public class ObjectService {
public void serviceMethodA() {
try {
synchronized (this) {
System.out
.println("A begin time=" + System.currentTimeMillis());
Thread.sleep(2000);
System.out
.println("A end end=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void serviceMethodB() {
synchronized (this) {
System.out.println("B begin time=" + System.currentTimeMillis());
System.out.println("B end end=" + System.currentTimeMillis());
}
}
}
ThreadA
package com.weishiyao.learn.day4.testSynchorized.ep3;
public class ThreadA extends Thread {
private ObjectService service;
public ThreadA(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodA();
}
}
ThreadB
package com.weishiyao.learn.day4.testSynchorized.ep3;
public class ThreadB extends Thread {
private ObjectService service;
public ThreadB(ObjectService service) {
super();
this.service = service;
}
@Override
public void run() {
super.run();
service.serviceMethodB();
}
}
Run
package com.weishiyao.learn.day4.testSynchorized.ep3;
public class Run {
public static void main(String[] args) {
ObjectService service = new ObjectService();
ThreadA a = new ThreadA(service);
a.setName("a");
a.start();
ThreadB b = new ThreadB(service);
b.setName("b");
b.start();
}
}
结果
A begin time=1459077186249
A end end=1459077188249
B begin time=1459077188249
B end end=1459077188249
三、静态同步synchronized方法与synchronized(class)代码块
关键字synchronized还可以用在static静态方法上,如果这样写,那是对当前的java对应的Class类进行上锁
Service类
package com.weishiyao.learn.day4.staticSynchorized;
public class Service {
synchronized public static void printA() {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入A");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开A");
} catch (Exception e) {
e.printStackTrace();
}
}
synchronized public static void printB() {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入B");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开B");
} catch (Exception e) {
e.printStackTrace();
}
}
synchronized public void printC() {
try {
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入C");
Thread.sleep(3000);
System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开C");
} catch (Exception e) {
e.printStackTrace();
}
}
}
ThreadA
package com.weishiyao.learn.day4.staticSynchorized;
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
super();
this.service = service;
}
@SuppressWarnings("static-access")
@Override
public void run() {
service.printA();
}
}
ThreadB、ThreadC类似ThreadA,不再列出
Run
package com.weishiyao.learn.day4.staticSynchorized;
public class Run {
public static void main(String[] args) {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadB.start();
ThreadC threadC = new ThreadC(service);
threadC.setName("C");
threadC.start();
}
}
结果
线程名称为:A在1459078101483进入A
线程名称为:C在1459078101490进入C
线程名称为:A在1459078104484离开A
线程名称为:B在1459078104484进入B
线程名称为:C在1459078104491离开C
线程名称为:B在1459078107484离开B
分析运行结果,A和B是同步运行,C是异步运行,异步的原因是持有不同的锁,一个是对象锁,另外一个是Class锁。
同步synchronized(class)代码块的作用和synchronized static方法的作用一样。
四、内置类与同步
OutClass
package com.weishiyao.learn.day4.syncClass.ep5;
public class OutClass {
static class InnerClass1 {
public void method1(InnerClass2 class2) {
String threadName = Thread.currentThread().getName();
synchronized (class2) {
System.out.println(threadName
+ " 进入InnerClass1类中的method1方法");
for (int i = 0; i < 10; i++) {
System.out.println("i=" + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(threadName
+ " 离开InnerClass1类中的method1方法");
}
}
public synchronized void method2() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 进入InnerClass1类中的method2方法");
for (int j = 0; j < 10; j++) {
System.out.println("j=" + j);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(threadName + " 离开InnerClass1类中的method2方法");
}
}
static class InnerClass2 {
public synchronized void method1() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 进入InnerClass2类中的method1方法");
for (int k = 0; k < 10; k++) {
System.out.println("k=" + k);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
System.out.println(threadName + " 离开InnerClass2类中的method1方法");
}
}
}
Run
package com.weishiyao.learn.day4.syncClass.ep5; import com.weishiyao.learn.day4.syncClass.ep5.OutClass.InnerClass1;
import com.weishiyao.learn.day4.syncClass.ep5.OutClass.InnerClass2; public class Run { public static void main(String[] args) {
final InnerClass1 in1 = new InnerClass1();
final InnerClass2 in2 = new InnerClass2();
Thread t1 = new Thread(new Runnable() {
public void run() {
in1.method1(in2);
}
}, "T1");
Thread t2 = new Thread(new Runnable() {
public void run() {
in1.method2();
}
}, "T2");
Thread t3 = new Thread(new Runnable() {
public void run() {
in2.method1();
}
}, "T3");
t1.start();
t2.start();
t3.start();
}
}
结果
T2 进入InnerClass1类中的method2方法
T1 进入InnerClass1类中的method1方法
i=0
j=0
i=1
j=1
j=2
i=2
i=3
j=3
j=4
i=4
i=5
j=5
j=6
i=6
i=7
j=7
i=8
j=8
i=9
j=9
T2 离开InnerClass1类中的method2方法
T1 离开InnerClass1类中的method1方法
T3 进入InnerClass2类中的method1方法
k=0
k=1
k=2
k=3
k=4
k=5
k=6
k=7
k=8
k=9
T3 离开InnerClass2类中的method1方法
同步代码块synchronized(class2)对class2上锁后,其他线程只能以同步的方式调用class2中的静态同步方法
五、锁对象的改变
在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。
MyService
package com.weishiyao.learn.day4.syncClass.ep6;
public class MyService {
private String lock = "123";
public void testMethod() {
try {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " begin "
+ System.currentTimeMillis());
lock = "456";
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " end "
+ System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadA
package com.weishiyao.learn.day4.syncClass.ep6;
public class ThreadA extends Thread {
private MyService service;
public ThreadA(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
ThreadB
package com.weishiyao.learn.day4.syncClass.ep6;
public class ThreadB extends Thread {
private MyService service;
public ThreadB(MyService service) {
super();
this.service = service;
}
@Override
public void run() {
service.testMethod();
}
}
Run1
package com.weishiyao.learn.day4.syncClass.ep6;
public class Run1 {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadB b = new ThreadB(service);
b.setName("B");
a.start();
Thread.sleep(50);
b.start();
}
}
结果
A begin 1459080143796
B begin 1459080143846
A end 1459080145797
B end 1459080145846
因为50毫秒之后a取得的是锁"456"
重新改一下Run类
package com.weishiyao.learn.day4.syncClass.ep6;
public class Run2 {
public static void main(String[] args) throws InterruptedException {
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadB b = new ThreadB(service);
b.setName("B");
a.start();
b.start();
}
}
结果
A begin 1459080318782
A end 1459080320782
B begin 1459080320782
B end 1459080322783
只要对象不变,即使对象的属性被改变,运行结果还是同步的
Service
package com.weishiyao.learn.day4.syncClass.ep7;
public class Service {
public void serviceMethodA(Userinfo userinfo) {
synchronized (userinfo) {
try {
System.out.println(Thread.currentThread().getName());
userinfo.setUsername("abcabcabc");
Thread.sleep(3000);
System.out.println("end! time=" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Userinfo
package com.weishiyao.learn.day4.syncClass.ep7;
public class Userinfo {
private String username;
private String password;
public Userinfo() {
super();
}
public Userinfo(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
ThreadA
package com.weishiyao.learn.day4.syncClass.ep7;
public class ThreadA extends Thread {
private Service service;
private Userinfo userinfo;
public ThreadA(Service service,
Userinfo userinfo) {
super();
this.service = service;
this.userinfo = userinfo;
}
@Override
public void run() {
service.serviceMethodA(userinfo);
}
}
ThreadB
package com.weishiyao.learn.day4.syncClass.ep7;
public class ThreadB extends Thread {
private Service service;
private Userinfo userinfo;
public ThreadB(Service service,
Userinfo userinfo) {
super();
this.service = service;
this.userinfo = userinfo;
}
@Override
public void run() {
service.serviceMethodA(userinfo);
}
}
运行类
package com.weishiyao.learn.day4.syncClass.ep7;
public class Run {
public static void main(String[] args) {
try {
Service service = new Service();
Userinfo userinfo = new Userinfo();
ThreadA a = new ThreadA(service, userinfo);
a.setName("a");
a.start();
Thread.sleep(50);
ThreadB b = new ThreadB(service, userinfo);
b.setName("b");
b.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果
a
end! time=1459080585999
b
end! time=1459080589000
java多线程(三)——锁机制synchronized(同步语句块)的更多相关文章
- java多线程(二)——锁机制synchronized(同步方法)
synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中 ...
- JAVA多线程与锁机制
JAVA多线程与锁机制 1 关于Synchronized和lock synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码 ...
- “全栈2019”Java多线程第二十一章:同步代码块产生死锁的例子
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十八章:同步代码块双重判断详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- synchronized同步语句块
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长时间.在这样的情况下可以使用synchronized同步语句块来解 ...
- 【转载】Java中的锁机制 synchronized & 偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景 & AtomicReference
参考文章: http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接 ...
- (原创)JAVA多线程三锁
前两章介绍了锁,那么现在我们介绍新的一个类,锁 一,简介 Lock是一个接口,实现它的类有读锁,写锁,和ReentrantLock,我们可以在类上点击ctrl+t来看看有哪些类实现了这个接口 使用方法 ...
- “全栈2019”Java多线程第十七章:同步锁详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- java synchronized静态同步方法与非静态同步方法,同步语句块
摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...
随机推荐
- 在SpringMVC中获取request对象的几种方式
1.最简单的方式(注解法) @Autowired private HttpServletRequest request; 2.最麻烦的方法 a. 在web.xml中配置一个监听 <listene ...
- eclipse从数据库逆向生成Hibernate实体类
做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再“自己”建立一变VO.意思是,在项目设计时,要么 ...
- 如何让DevExpress TreeList的每个结点高亮显示?
概述:如何让DevExpress TreeList的每个节点高亮显示? 如何让DXperience TreeList的每个节点高亮显示? 效果如下: private void treeList1_Cu ...
- 【eoe 6】ActionBar的使用
一. Action Bar 一般位于屏幕顶部,包括四个可操作区域: 应用图标或LOGO区域,用于视图控制的Spinner下拉菜单或TAB控件区域, Action button(也称为Action It ...
- Code the Tree(图论,树)
ZOJ Problem Set - 1097 Code the Tree Time Limit: 2 Seconds Memory Limit: 65536 KB A tree (i.e. ...
- nginx重定向规则入门
nginx重定向规则的入门实例 时间:2015-12-17 15:18:03来源:网络 导读:nginx重定向规则,Nginx的重定向模块HttpRewriteModule的用法说明,nginx重定向 ...
- 10个TWaver 网页3D可视化精彩案例
以下网页3D案例均为TWaver原创出品,推荐使用Chrome, FireFox, Safari等对WebGL支持良好的浏览器运行.案例排名不分先后,如需Demo,可直接申请试用. 1. 化学元素 ...
- 在Visual Studio 2010中进行“项目重命名”的有效工具
地址:http://www.cnblogs.com/dudu/archive/2011/12/11/visual_studio_2010_project_rename.html 提示:这个工具一次 r ...
- SecureCRT rz 上传文件失败问题
在把Windows上的文件传至Linux端时用到SecureCRT,一般小文件都没有问题,文件太大时则出现了上传后的文件只有几K大小,当然大于2个G的是不可能传的上去的了.对于几百M到1G多的大文件要 ...
- excel导入记录
use DangJianSELECT vale1, value2 into Table2 from Table1 select COUNT(*) from tmpdangyuan where 手机号 ...