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 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...
随机推荐
- DataGridView中添加CheckBox列用于选择行
DataGridView中添加CheckBox列用于选择行 1,编辑DataGridView,添加一列 CheckBox ,Name 赋值为 "select",如下图: 2,取消 ...
- 【经验谈】XmlSerializer的坑
XmlSerializer我想现在用的人可能不多了,大家都在用Json.我现在所在的公司依然在用,所以发现了这个坑.当然这个坑存在很久了只是没用过所以才发现. 事情是这样的,测试那边说系统偶尔会报找不 ...
- offsetof的使用
#include <stddef.h> #define offsetof ( TYPE, m) (size_t )&reinterpret_cast< const vol ...
- ux.plugin.ConTpl 模版元素监听扩展
/* *tpl模版加入按钮 *<div class="x-button-normal x-button x-iconalign-center x-layout-box-item x-s ...
- (转)使用Custom Draw实现ListCtrl的重绘
使用Custom Draw实现ListCtrl的重绘 common control 4.7版本介绍了一个新的特性叫做Custom Draw,这个名字显得模糊不清,让人有点摸不着头脑,而且MSDN里 ...
- POJ 1330 Nearest Common Ancestors
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14698 Accept ...
- nginx 常用配置说明
一.location 配置 1.1 语法规则: location [=|~|~*|^~] /uri/ { … }= 开头表示精确匹配^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可 ...
- 基于Java的数据采集(终结篇)
关于写过关于JAVA采集入库的三篇文章: 基于Java数据采集入库(一):http://www.cnblogs.com/lichenwei/p/3904715.html 基于Java数据采集入库(二) ...
- Log4net对文件的支持
RollingFileAppender循环记录日志(指定文件最大长度) <appender name="RollingFileAppender" type="log ...
- android判断EditText输入的数字、中文还是字母方法
String txt = edInput.getText().toString(); Pattern p = Pattern.compile("[0-9]*"); Mat ...