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 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...
随机推荐
- struts2:JSP页面及Action中获取HTTP参数(parameter)的几种方式
本文演示了JSP中获取HTTP参数的几种方式,还有action中获取HTTP参数的几种方式. 1. 创建JSP页面(testParam.jsp) <%@ page language=" ...
- 大型网站系统架构演化之路【mark】
前言 一 个成熟的大型网站(如淘宝.天猫.腾讯等)的系统架构并不是一开始设计时就具备完整的高性能.高可用.高伸缩等特性的,它是随着用户量的增加,业务功能的 扩展逐渐演变完善的,在这个过程中,开发模式. ...
- Hbase0.98.4/Hadoop2.4.1整合小结【原创】
设定hbase的数据目录,修改conf/hbase-site.xml <configuration> <property> <name>hbase.cluster. ...
- [Z] 北大一牛人生物转申CS的经历
http://www.bdwm.net/bbs/bbscon.php?board=CIS&file=M.1367038121.A&num=626&attach=0&di ...
- java之Object类介绍
1.Object类是所有java类的基类 如果在类的声明中未使用extends关键字指明其基类,则默认基类为Object类,ex: public class Person{ ~~~~~ } 等价于 p ...
- Mysql 导入数据,推荐Source命令,太快了
http://jingyan.baidu.com/article/cbf0e500d15c762eab289362.html
- Android SDK开发包国内下载地址
不知道是因为最近kaihui还是怎么的,打开android sdk官方网站特别的慢,想下载最新版本的platform几乎变成不可能完成的任务,不知道为什么Google不像Apache那样在各国设立镜像 ...
- Form personization(Form 个性化)报无权限
总部的同事利用form personization对工单的一些Form做了个性化,发现可能设的有问题,造成用户无法关工单.想要看一下她是怎么设的,可报没权限.经过研究发现,把个人Profile 的 U ...
- WEB安全入门(转)
一. 首先你得了解Web Web分为好几层,一图胜千言:事实是这样的:如果你不了解这些研究对象是不可能搞好安全研究的.这样看来,Web有八层(如果把浏览器也算进去,就九层啦,九阳神功……)!!!每层都 ...
- VMware下OS X Yosemite安装VMsvga2桌面黑屏解决方法
VMsvga2目前并不支持Yosemite,如果安装的话进入桌面除了顶部菜单,全部黑屏.通过顶部菜单打开的大部分应用都会立刻奔溃关闭.参考以下步骤可以解决问题: 1.下载VMsvga2的uninsta ...