用关键字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(同步语句块)的更多相关文章

  1. java多线程(二)——锁机制synchronized(同步方法)

    synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中 ...

  2. JAVA多线程与锁机制

    JAVA多线程与锁机制 1 关于Synchronized和lock synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码 ...

  3. “全栈2019”Java多线程第二十一章:同步代码块产生死锁的例子

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. “全栈2019”Java多线程第十八章:同步代码块双重判断详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. synchronized同步语句块

    用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B线程则必须等待比较长时间.在这样的情况下可以使用synchronized同步语句块来解 ...

  6. 【转载】Java中的锁机制 synchronized & 偏向锁 & 轻量级锁 & 重量级锁 & 各自优缺点及场景 & AtomicReference

    参考文章: http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接 ...

  7. (原创)JAVA多线程三锁

    前两章介绍了锁,那么现在我们介绍新的一个类,锁 一,简介 Lock是一个接口,实现它的类有读锁,写锁,和ReentrantLock,我们可以在类上点击ctrl+t来看看有哪些类实现了这个接口 使用方法 ...

  8. “全栈2019”Java多线程第十七章:同步锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  9. java synchronized静态同步方法与非静态同步方法,同步语句块

    摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...

随机推荐

  1. Maven3路程(二)Eclipse集成Maven

    我的环境: Eclipse:eclipse-jee-juno-SR2-win32 Maven:Maven3.0.5 1.Help->Eclipse Marketplace 2.选中要安装的插件, ...

  2. c#上iOS apns p12文件制作记录

    1.在桌面上建一个"apns_p12"文件夹,所有的保存和生成文件都放在这里 2.从钥匙串中生成CertificateSigningRequest.certSigningReque ...

  3. 【汇总】涉及iOS&iPhone开发相关文章汇总

    此文章汇总本博客中有涉及iPhone开发的相关文章,不定时更新中... 1.NSUserDefaults快速存储数据: http://www.cnblogs.com/ios-wmm/archive/2 ...

  4. WinStore控件之TextBlock

    1  TextBlock简单实例应用 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}&quo ...

  5. unity web player的debug和log信息

    win8模式下 unity web player的报错信息在如下目录下:C:\Users\xxx\AppData\Local\Temp\UnityWebPlayer\log 注:目录里的文件可能被隐藏 ...

  6. Ubuntu 配置AP总结

    1.这个是使用别人写的一个GUI来配置,:http://hi.baidu.com/lexiangtaotao/item/5d4e87f22db132c70cd1c86f 2.使用hostapd配置:h ...

  7. SQL 触发器 instead of | insert

    create trigger tgr_Insert on A instead of insert as print 'Hello World' go insert into A values('100 ...

  8. 解决 -ERR Plaintext authentication disallowed on non-secure (SSL/TLS) connections 方案[sendmail, dovecot]

    在linux下安装sendmail比较容易, 但是在配置sendmail时却是比较麻烦的, 特别是对于一些新手来说, 配置过程必须十分小心谨慎, 要知道, 错误是千奇百怪, 但是成功的结果就只有一个, ...

  9. ArcGIS Server注册地理数据库报machine:机器名[Oracle:(null)]错误的修改

    环境介绍:本机安装了ArcGIS Server10.2,ArcGIS Desktop10.2,64位Oracle11g以及Oracle32位客户端.直连和服务连接都能成功. 问题:我要进行服务发布的时 ...

  10. hdu 2152

    题目大意:本题是中文题.读者可以直接到OJ上去阅读.提议并不难理解 代码如下: /* * 2152_1.cpp * * Created on: 2013年8月9日 * Author: Administ ...