多线程时synchronized到底应该锁定什么对象?

  1 import org.junit.Test;
  2 
  3 import java.sql.Timestamp;
  4 import java.util.HashMap;
  5 import java.util.Map;
  6 import java.util.concurrent.Executor;
  7 import java.util.concurrent.ExecutorService;
  8 import java.util.concurrent.Executors;
  9 import java.util.concurrent.TimeUnit;
 10 
 11 /**
 12  * @Description: synchronized加锁的对象测试
 13  * @date: 2020-02-20 16:38
 14  * @author: yff
 15  */
 16 
 17 /*
 18 * synchronized
 19 *   1,锁定普通方法时,锁定的是当前对象,仅对当前对象生效,当不同对象(用new创建出来的对象),来执行代码时,不能锁定代码,不能保证只有一个线程进入
 20 *   2,锁定static时,锁定的是class类,不管创建几个相同类的对象来执行代码,都只能有一个线程进入
 21 *   3(实验目的),锁定特定对象时,只能是最先拥有这个对象的线程才能进入
 22 *先说一下业务要求:一次请求,在后台生成多线程同时查库,然后把多个查库的结果同时塞入map中。全程没有写库的操作。
 23 *例如代码中,通过主类启动两个线程(模拟两个请求),每个请求创建各自的线程池处理各自的业务(互不能影响),各自的线程池再创建各自的两(多)个Runnable任务(提升效率)。
 24 * 注意:TestRunnable中的map是临界资源
 25 *总计两个线程池     pool1   与   pool  2  ,
 26 *   四个线程  pool1-thread-1    pool1-thread-2   pool2-thread-1    pool2-thread-2
 27 *   ①当synchronized锁定this对象时:四个线程能相互影响,数据完全混乱,不符合业务要求
 28 *   ②当synchronized锁定TestRunnable.class类时:四个线程全都相互排斥,能保证数据安全
 29 *但是多线程的目的原本是想让一个请求(线程池)中的两个线程相互协调提升效率。如果这样加锁,
 30 *就会造成请求A在操作临界资源时,虽然可以让相同线程池中的其他线程排队等待,但是也会使其他请求中的多个线程也一并在外排队等待。
 31 *而实际情况是,每次请求都会声明一个map,多个请求之间并不会相互影响,因为它们操作两个map。
 32 *   ③当synchronized锁定map时:同一个线程池中的线程相互等待,不同线程池的线程可以同时执行代码块。这也恰好符合业务逻辑,
 33 *每个请求声明多个线程同时协作,在临界资源时等待。不同请求由于操作的资源不是同一个,所以不必相互等待(指的是塞入的不是一个map,但如果有写库场景的话需要等待)。
 34 *把库看成map,如果写入操作是一个临界资源,则要等待,相当于一个线程池中的线程相互等待,如果写入的是多个map,则可以看成多个库,自然不用相互等待,道理都是一样的,活学活用吧。
 35 * */
 36 public class Main {
 37 
 38 
 39     @Test
 40     public void main() {
 41         Thread testThread = new TestThread();
 42         testThread.setName("启动线程1");
 43         testThread.start();
 44         Thread testThread2 = new TestThread();
 45         testThread2.setName("启动线程2");
 46         testThread2.start();
 47         try {
 48             testThread.join();
 49             testThread2.join();
 50         } catch (InterruptedException e) {
 51             System.err.println("error!!!!!!!!!");
 52         }finally {
 53             System.out.println("main结束了");
 54         }
 55     }
 56 
 57 
 58     class TestThread extends Thread {
 59         @Override
 60         public void run() {
 61             Executor executor;
 62             synchronized (TestThread.class){
 63                 System.out.println(new Timestamp(System.currentTimeMillis())+Thread.currentThread().getName()+"先进入了run创建了pool");
 64                 executor = Executors.newFixedThreadPool(4);
 65             }
 66             Map map = new HashMap(4);
 67             map.put("key1", "value1");
 68             map.put("key2", "value2");
 69             Runnable t1 = new TestRunnable(map);
 70             Runnable t2 = new TestRunnable(map);
 71             executor.execute(t1);
 72             executor.execute(t2);
 73             try {
 74                 ((ExecutorService) executor).shutdown();
 75                 boolean flag;
 76                 while (true) {
 77                     flag = ((ExecutorService) executor).awaitTermination(4, TimeUnit.SECONDS);
 78                     if (flag) {
 79                         System.out.println(new Timestamp(System.currentTimeMillis())+Thread.currentThread().getName()+"终于执行完了");
 80                         break;
 81                     }else{
 82                         System.out.println(new Timestamp(System.currentTimeMillis())+Thread.currentThread().getName()+"还没有执行完");
 83                     }
 84                 }
 85             } catch (InterruptedException e) {
 86                 System.err.println("error!!!!!!!!!!!");
 87             } finally {
 88                 System.out.println(new Timestamp(System.currentTimeMillis())+Thread.currentThread().getName()+"Thread结束了");
 89             }
 90         }
 91     }
 92 
 93     class TestRunnable implements Runnable {
 94 
 95         private Map map;
 96 
 97         public TestRunnable(Map map) {
 98             this.map = map;
 99         }
100 
101         @Override
102         public void run() {
103             synchronized (map) {
104                 try {
105                     System.out.println(new Timestamp(System.currentTimeMillis())+Thread.currentThread().getName()+"线程开始睡眠3秒");
106                     Thread.sleep(3000);
107                     System.out.println(new Timestamp(System.currentTimeMillis())+Thread.currentThread().getName()+"线程结束睡眠3秒");
108                 } catch (InterruptedException e) {
109                     System.err.println("error!!!!!!!");
110                 }
111             }
112         }
113     }
114 
115 }

 

posted @ 2020-07-09 17:23  菲菲一个  阅读(476)  评论(0编辑  收藏  举报