java多线程(三)——锁机制synchronized(同步语句块)

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

一、用同步代码块解决同步方法的弊端

Task类

 1 package com.weishiyao.learn.day4.testSynchorized.ep2;
 2
 3 public class Task {
 4
 5     private String getData1;
 6     private String getData2;
 7
 8     public void doLongTimeTask() {
 9         try {
10             System.out.println("begin task");
11             Thread.sleep(3000);
12
13             String privateGetData1 = "长时间处理任务后从远程返回的值1 threadName="
14                     + Thread.currentThread().getName();
15             String privateGetData2 = "长时间处理任务后从远程返回的值2 threadName="
16                     + Thread.currentThread().getName();
17
18             synchronized (this) {
19                 getData1 = privateGetData1;
20                 getData2 = privateGetData2;
21             }
22
23             System.out.println(getData1);
24             System.out.println(getData2);
25             System.out.println("end task");
26         } catch (InterruptedException e) {
27             e.printStackTrace();
28         }
29     }
30 }

常量工具类

 1 package com.weishiyao.learn.day4.testSynchorized.ep2;
 2
 3 public class CommonUtils {
 4
 5     public static long beginTime1;
 6     public static long endTime1;
 7
 8     public static long beginTime2;
 9     public static long endTime2;
10 }

线程类——2个

 1 package com.weishiyao.learn.day4.testSynchorized.ep2;
 2
 3 public class MyThread1 extends Thread {
 4
 5     private Task task;
 6
 7     public MyThread1(Task task) {
 8         super();
 9         this.task = task;
10     }
11
12     @Override
13     public void run() {
14         super.run();
15         CommonUtils.beginTime1 = System.currentTimeMillis();
16         task.doLongTimeTask();
17         CommonUtils.endTime1 = System.currentTimeMillis();
18     }
19
20 }
 1 package com.weishiyao.learn.day4.testSynchorized.ep2;
 2
 3 public class MyThread2 extends Thread {
 4
 5     private Task task;
 6
 7     public MyThread2(Task task) {
 8         super();
 9         this.task = task;
10     }
11
12     @Override
13     public void run() {
14         super.run();
15         CommonUtils.beginTime2 = System.currentTimeMillis();
16         task.doLongTimeTask();
17         CommonUtils.endTime2 = System.currentTimeMillis();
18     }
19
20 }

运行类

 1 package com.weishiyao.learn.day4.testSynchorized.ep2;
 2
 3 public class Run {
 4
 5     public static void main(String[] args) {
 6         Task task = new Task();
 7
 8         MyThread1 thread1 = new MyThread1(task);
 9         thread1.start();
10
11         MyThread2 thread2 = new MyThread2(task);
12         thread2.start();
13
14         try {
15             Thread.sleep(10000);
16         } catch (InterruptedException e) {
17             e.printStackTrace();
18         }
19
20         long beginTime = CommonUtils.beginTime1;
21         if (CommonUtils.beginTime2 < CommonUtils.beginTime1) {
22             beginTime = CommonUtils.beginTime2;
23         }
24
25         long endTime = CommonUtils.endTime1;
26         if (CommonUtils.endTime2 > CommonUtils.endTime1) {
27             endTime = CommonUtils.endTime2;
28         }
29
30         System.out.println("耗时" + ((endTime - beginTime) / 1000) + " 秒");
31     }
32 }

结果

1 begin task
2 begin task
3 长时间处理任务后从远程返回的值1 threadName=Thread-1
4 长时间处理任务后从远程返回的值1 threadName=Thread-0
5 长时间处理任务后从远程返回的值2 threadName=Thread-0
6 长时间处理任务后从远程返回的值2 threadName=Thread-0
7 end task
8 end task
9 耗时3 秒

这里是用的synchronized代码锁,如果换成方法锁

所有代码不变,仅更改Task类

 1 package com.weishiyao.learn.day4.testSynchorized.ep2;
 2
 3 public class Task {
 4
 5     private String getData1;
 6     private String getData2;
 7
 8     public synchronized void doLongTimeTask() {
 9         try {
10             System.out.println("begin task");
11             Thread.sleep(3000);
12             getData1 = "长时间处理任务后从远程返回的值1 threadName="
13                     + Thread.currentThread().getName();
14             getData2 = "长时间处理任务后从远程返回的值2 threadName="
15                     + Thread.currentThread().getName();
16             System.out.println(getData1);
17             System.out.println(getData2);
18             System.out.println("end task");
19         } catch (InterruptedException e) {
20             // TODO Auto-generated catch block
21             e.printStackTrace();
22         }
23     }
24 }

运行结果

1 begin task
2 长时间处理任务后从远程返回的值1 threadName=Thread-0
3 长时间处理任务后从远程返回的值2 threadName=Thread-0
4 end task
5 begin task
6 长时间处理任务后从远程返回的值1 threadName=Thread-1
7 长时间处理任务后从远程返回的值2 threadName=Thread-1
8 end task
9 耗时6 秒

可以得出结论,当一个线程访问object的synchronized同步代码块时,另一个线程依然可以访问非同步代码块,这样同步代码块就会比同步方法所花费更短的时间,可以得到更高的效率,在同步代码块中代码是同步的,不在同步代码块中代码是异步的。

二、synchronized代码块间的同步性

当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,因为synchronized使用的是一个“对象监视器”

ObjectService类

 1 package com.weishiyao.learn.day4.testSynchorized.ep3;
 2
 3 public class ObjectService {
 4
 5     public void serviceMethodA() {
 6         try {
 7             synchronized (this) {
 8                 System.out
 9                         .println("A begin time=" + System.currentTimeMillis());
10                 Thread.sleep(2000);
11                 System.out
12                         .println("A end    end=" + System.currentTimeMillis());
13             }
14         } catch (InterruptedException e) {
15             e.printStackTrace();
16         }
17     }
18
19     public void serviceMethodB() {
20         synchronized (this) {
21             System.out.println("B begin time=" + System.currentTimeMillis());
22             System.out.println("B end    end=" + System.currentTimeMillis());
23         }
24     }
25 }

ThreadA

 1 package com.weishiyao.learn.day4.testSynchorized.ep3;
 2
 3 public class ThreadA extends Thread {
 4
 5     private ObjectService service;
 6
 7     public ThreadA(ObjectService service) {
 8         super();
 9         this.service = service;
10     }
11
12     @Override
13     public void run() {
14         super.run();
15         service.serviceMethodA();
16     }
17
18 }

ThreadB

 1 package com.weishiyao.learn.day4.testSynchorized.ep3;
 2
 3 public class ThreadB extends Thread {
 4     private ObjectService service;
 5
 6     public ThreadB(ObjectService service) {
 7         super();
 8         this.service = service;
 9     }
10
11     @Override
12     public void run() {
13         super.run();
14         service.serviceMethodB();
15     }
16 }

Run

 1 package com.weishiyao.learn.day4.testSynchorized.ep3;
 2
 3 public class Run {
 4
 5     public static void main(String[] args) {
 6         ObjectService service = new ObjectService();
 7
 8         ThreadA a = new ThreadA(service);
 9         a.setName("a");
10         a.start();
11
12         ThreadB b = new ThreadB(service);
13         b.setName("b");
14         b.start();
15     }
16
17 }

结果

1 A begin time=1459077186249
2 A end    end=1459077188249
3 B begin time=1459077188249
4 B end    end=1459077188249

三、静态同步synchronized方法与synchronized(class)代码块

关键字synchronized还可以用在static静态方法上,如果这样写,那是对当前的java对应的Class类进行上锁

Service类

 1 package com.weishiyao.learn.day4.staticSynchorized;
 2
 3 public class Service {
 4     synchronized public static void printA() {
 5         try {
 6             System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入A");
 7             Thread.sleep(3000);
 8             System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开A");
 9         } catch (Exception e) {
10             e.printStackTrace();
11         }
12     }
13
14     synchronized public static void printB() {
15         try {
16             System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入B");
17             Thread.sleep(3000);
18             System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开B");
19         } catch (Exception e) {
20             e.printStackTrace();
21         }
22     }
23
24     synchronized public void printC() {
25         try {
26             System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "进入C");
27             Thread.sleep(3000);
28             System.out.println("线程名称为:" + Thread.currentThread().getName() + "在" + System.currentTimeMillis() + "离开C");
29         } catch (Exception e) {
30             e.printStackTrace();
31         }
32     }
33 }

ThreadA

 1 package com.weishiyao.learn.day4.staticSynchorized;
 2
 3 public class ThreadA extends Thread {
 4     private Service service;
 5
 6     public ThreadA(Service service) {
 7         super();
 8         this.service = service;
 9     }
10
11     @SuppressWarnings("static-access")
12     @Override
13     public void run() {
14         service.printA();
15     }
16 }

ThreadB、ThreadC类似ThreadA,不再列出

Run

 1 package com.weishiyao.learn.day4.staticSynchorized;
 2
 3 public class Run {
 4     public static void main(String[] args) {
 5         Service service = new Service();
 6         ThreadA threadA = new ThreadA(service);
 7         threadA.setName("A");
 8         threadA.start();
 9         ThreadB threadB = new ThreadB(service);
10         threadB.setName("B");
11         threadB.start();
12         ThreadC threadC = new ThreadC(service);
13         threadC.setName("C");
14         threadC.start();
15     }
16 }

结果

1 线程名称为:A在1459078101483进入A
2 线程名称为:C在1459078101490进入C
3 线程名称为:A在1459078104484离开A
4 线程名称为:B在1459078104484进入B
5 线程名称为:C在1459078104491离开C
6 线程名称为:B在1459078107484离开B

分析运行结果,A和B是同步运行,C是异步运行,异步的原因是持有不同的锁,一个是对象锁,另外一个是Class锁。

同步synchronized(class)代码块的作用和synchronized static方法的作用一样。

四、内置类与同步

OutClass

 1 package com.weishiyao.learn.day4.syncClass.ep5;
 2
 3 public class OutClass {
 4     static class InnerClass1 {
 5         public void method1(InnerClass2 class2) {
 6             String threadName = Thread.currentThread().getName();
 7             synchronized (class2) {
 8                 System.out.println(threadName
 9                         + " 进入InnerClass1类中的method1方法");
10                 for (int i = 0; i < 10; i++) {
11                     System.out.println("i=" + i);
12                     try {
13                         Thread.sleep(100);
14                     } catch (InterruptedException e) {
15
16                     }
17                 }
18                 System.out.println(threadName
19                         + " 离开InnerClass1类中的method1方法");
20             }
21         }
22
23         public synchronized void method2() {
24             String threadName = Thread.currentThread().getName();
25             System.out.println(threadName + " 进入InnerClass1类中的method2方法");
26             for (int j = 0; j < 10; j++) {
27                 System.out.println("j=" + j);
28                 try {
29                     Thread.sleep(100);
30                 } catch (InterruptedException e) {
31
32                 }
33             }
34             System.out.println(threadName + " 离开InnerClass1类中的method2方法");
35         }
36     }
37
38     static class InnerClass2 {
39         public synchronized void method1() {
40             String threadName = Thread.currentThread().getName();
41             System.out.println(threadName + " 进入InnerClass2类中的method1方法");
42             for (int k = 0; k < 10; k++) {
43                 System.out.println("k=" + k);
44                 try {
45                     Thread.sleep(100);
46                 } catch (InterruptedException e) {
47
48                 }
49             }
50             System.out.println(threadName + " 离开InnerClass2类中的method1方法");
51         }
52     }
53 }

Run

 1 package com.weishiyao.learn.day4.syncClass.ep5;
 2
 3 import com.weishiyao.learn.day4.syncClass.ep5.OutClass.InnerClass1;
 4 import com.weishiyao.learn.day4.syncClass.ep5.OutClass.InnerClass2;
 5
 6 public class Run {
 7
 8     public static void main(String[] args) {
 9         final InnerClass1 in1 = new InnerClass1();
10         final InnerClass2 in2 = new InnerClass2();
11         Thread t1 = new Thread(new Runnable() {
12             public void run() {
13                 in1.method1(in2);
14             }
15         }, "T1");
16         Thread t2 = new Thread(new Runnable() {
17             public void run() {
18                 in1.method2();
19             }
20         }, "T2");
21         Thread t3 = new Thread(new Runnable() {
22             public void run() {
23                 in2.method1();
24             }
25         }, "T3");
26         t1.start();
27         t2.start();
28         t3.start();
29     }
30 }

结果

 1 T2 进入InnerClass1类中的method2方法
 2 T1 进入InnerClass1类中的method1方法
 3 i=0
 4 j=0
 5 i=1
 6 j=1
 7 j=2
 8 i=2
 9 i=3
10 j=3
11 j=4
12 i=4
13 i=5
14 j=5
15 j=6
16 i=6
17 i=7
18 j=7
19 i=8
20 j=8
21 i=9
22 j=9
23 T2 离开InnerClass1类中的method2方法
24 T1 离开InnerClass1类中的method1方法
25 T3 进入InnerClass2类中的method1方法
26 k=0
27 k=1
28 k=2
29 k=3
30 k=4
31 k=5
32 k=6
33 k=7
34 k=8
35 k=9
36 T3 离开InnerClass2类中的method1方法

同步代码块synchronized(class2)对class2上锁后,其他线程只能以同步的方式调用class2中的静态同步方法

五、锁对象的改变

在将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的;如果分别获得锁对象,这些线程之间就是异步的。

MyService

 1 package com.weishiyao.learn.day4.syncClass.ep6;
 2
 3 public class MyService {
 4     private String lock = "123";
 5
 6     public void testMethod() {
 7         try {
 8             synchronized (lock) {
 9                 System.out.println(Thread.currentThread().getName() + " begin "
10                         + System.currentTimeMillis());
11                 lock = "456";
12                 Thread.sleep(2000);
13                 System.out.println(Thread.currentThread().getName() + "   end "
14                         + System.currentTimeMillis());
15             }
16         } catch (InterruptedException e) {
17             e.printStackTrace();
18         }
19     }
20
21 }

ThreadA

 1 package com.weishiyao.learn.day4.syncClass.ep6;
 2
 3 public class ThreadA extends Thread {
 4
 5     private MyService service;
 6
 7     public ThreadA(MyService service) {
 8         super();
 9         this.service = service;
10     }
11
12     @Override
13     public void run() {
14         service.testMethod();
15     }
16 }

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

 1 package com.weishiyao.learn.day4.syncClass.ep6;
 2
 3 public class Run1 {
 4
 5     public static void main(String[] args) throws InterruptedException {
 6
 7         MyService service = new MyService();
 8
 9         ThreadA a = new ThreadA(service);
10         a.setName("A");
11
12         ThreadB b = new ThreadB(service);
13         b.setName("B");
14
15         a.start();
16         Thread.sleep(50);
17         b.start();
18     }
19 }

结果

1 A begin 1459080143796
2 B begin 1459080143846
3 A   end 1459080145797
4 B   end 1459080145846

因为50毫秒之后a取得的是锁"456"

重新改一下Run类

 1 package com.weishiyao.learn.day4.syncClass.ep6;
 2
 3 public class Run2 {
 4
 5     public static void main(String[] args) throws InterruptedException {
 6
 7         MyService service = new MyService();
 8
 9         ThreadA a = new ThreadA(service);
10         a.setName("A");
11
12         ThreadB b = new ThreadB(service);
13         b.setName("B");
14
15         a.start();
16         b.start();
17     }
18 }

结果

1 A begin 1459080318782
2 A   end 1459080320782
3 B begin 1459080320782
4 B   end 1459080322783

只要对象不变,即使对象的属性被改变,运行结果还是同步的

Service

 1 package com.weishiyao.learn.day4.syncClass.ep7;
 2
 3 public class Service {
 4
 5     public void serviceMethodA(Userinfo userinfo) {
 6         synchronized (userinfo) {
 7             try {
 8                 System.out.println(Thread.currentThread().getName());
 9                 userinfo.setUsername("abcabcabc");
10                 Thread.sleep(3000);
11                 System.out.println("end! time=" + System.currentTimeMillis());
12             } catch (InterruptedException e) {
13                 e.printStackTrace();
14             }
15         }
16     }
17 }

Userinfo

 1 package com.weishiyao.learn.day4.syncClass.ep7;
 2
 3 public class Userinfo {
 4     private String username;
 5     private String password;
 6
 7     public Userinfo() {
 8         super();
 9     }
10
11     public Userinfo(String username, String password) {
12         super();
13         this.username = username;
14         this.password = password;
15     }
16
17     public String getUsername() {
18         return username;
19     }
20
21     public void setUsername(String username) {
22         this.username = username;
23     }
24
25     public String getPassword() {
26         return password;
27     }
28
29     public void setPassword(String password) {
30         this.password = password;
31     }
32
33 }

ThreadA

 1 package com.weishiyao.learn.day4.syncClass.ep7;
 2
 3 public class ThreadA extends Thread {
 4
 5     private Service service;
 6     private Userinfo userinfo;
 7
 8     public ThreadA(Service service,
 9             Userinfo userinfo) {
10         super();
11         this.service = service;
12         this.userinfo = userinfo;
13     }
14
15     @Override
16     public void run() {
17         service.serviceMethodA(userinfo);
18     }
19
20 }

ThreadB

 1 package com.weishiyao.learn.day4.syncClass.ep7;
 2
 3 public class ThreadB extends Thread {
 4
 5     private Service service;
 6     private Userinfo userinfo;
 7
 8     public ThreadB(Service service,
 9             Userinfo userinfo) {
10         super();
11         this.service = service;
12         this.userinfo = userinfo;
13     }
14
15     @Override
16     public void run() {
17         service.serviceMethodA(userinfo);
18     }
19
20 }

运行类

 1 package com.weishiyao.learn.day4.syncClass.ep7;
 2
 3 public class Run {
 4
 5     public static void main(String[] args) {
 6
 7         try {
 8             Service service = new Service();
 9             Userinfo userinfo = new Userinfo();
10
11             ThreadA a = new ThreadA(service, userinfo);
12             a.setName("a");
13             a.start();
14             Thread.sleep(50);
15             ThreadB b = new ThreadB(service, userinfo);
16             b.setName("b");
17             b.start();
18
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22
23     }
24 }

结果

1 a
2 end! time=1459080585999
3 b
4 end! time=1459080589000
时间: 2024-10-18 18:57:08

java多线程(三)——锁机制synchronized(同步语句块)的相关文章

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

synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行.另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块.然而,当一个线程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块. ——以上来源百度百科 一.方法内的变量为线程安全 “非线程安全”的问题

【转载】Java中的锁机制 synchronized &amp; Lock

参考文章: http://blog.csdn.net/chen77716/article/details/6618779 目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea.本文并不比较synchronized与Lock孰优孰劣,只是介绍二者的实现原理. 数据同步需要依赖锁,那锁的同步又依赖谁?synchronized给出的答案是在软件层面依赖JVM,而Lock给出的方案是在硬件层面依赖特殊的

java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)

import java.util.concurrent.locks.*; class DuckMsg{ int size;//烤鸭的大小 String id;//烤鸭的厂家和标号 DuckMsg(){ } DuckMsg(int size, String id){ this.size=size; this.id=id; } public String toString(){ return id + " 大小为:" + size; } } class Duck{ private int

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

摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方法,也可以选择同步块,这两种方式各有优缺点,至于具体选择什么方式,就见仁见智了,同步块不仅可以更加精确的控制对象锁,也就是控制锁的作用域,何谓锁的作用域?锁的作用域就是从锁被获取到其被释放的时间.而且可以选择要获取哪个对象的对象锁.但是如果在使用同步块机制时,如果使用过多的锁也会容易引起死锁问题,同

JAVA 的wait(), notify()与synchronized同步机制

转自:http://blog.csdn.net/zyplus/article/details/6672775 在JAVA中,是没有类似于PV操作.进程互斥等相关的方法的.JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized()方法类似于操作系统概念中的互斥内存块,在JAVA中的Object类型中,都是带有一个内存锁的,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步.互斥操作.明白这个原理,就能理解为什么syn

深入浅出Java并发包—锁机制(三)

接上文<深入浅出Java并发包—锁机制(二)>  由锁衍生的下一个对象是条件变量,这个对象的存在很大程度上是为了解决Object.wait/notify/notifyAll难以使用的问题. 条件(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”).因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联.等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并

转:JAVA 的wait(), notify()与synchronized同步机制

原文地址:http://blog.csdn.net/zyplus/article/details/6672775 转自:https://www.cnblogs.com/x_wukong/p/4009709.html 主要这句话 :Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用 在JAVA中,是没有类似于PV操作.进程互斥等相关的方法的.JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized

JAVA中的锁机制

Java中的锁 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂.因为锁(以及其它更高级的线程同步机制)是由synchronized同步块的方式实现的,所以我们还不能完全摆脱synchronized关键字(译者注:这说的是Java 5之前的情况). 自Java 5开始,java.util.concurrent.locks包中包含了一些锁的实现,因此你不用去实现自己的锁了.但是你仍然需要去了解怎样使用这些锁,且了解这些实现背后的理论也

Java 多线程(六) synchronized关键字详解

Java 多线程(六) synchronized关键字详解 多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchronized关键字修饰一个方法的时候,该方法叫做同步方法. 当synchronized方法执行完或发生异常时,会自动释放锁. 下面通过一个例子来对synchronized关键字的用法进行解析. 1.是否使用synchronized关键字的不同 例子