• 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
  • 相关阅读:
    数据流图
    数据库设计
    多媒体基础知识
    面向对象程序设计
    UML建模
    warning: integer overflow in expression [Woverflow]
    unmatched/skipped datagrams
    MFC
    D3DWindower
    cheatengine
  • 原文地址:https://www.cnblogs.com/babycomeon/p/5296794.html
Copyright © 2020-2023  润新知