zoukankan      html  css  js  c++  java
  • Java多线程之synchronized关键字

    一、synchronized锁住的不是代码块,是对象。
     1 /**
     2  * synchronized 对某个对象加锁
     3  */
     4 public class SynchronizedTest {
     5 
     6     private int count = 10;
     7     private Object o = new Object();
     8 
     9     private void method() {
    10         synchronized (o) { //任何线程想执行下面这段代码都需要拿到o这把锁
    11             count--;
    12             System.out.println(Thread.currentThread().getName() + " count=" + count);
    13         }
    14     }
    15 
    16 }

    二、synchronized是可重入的。

     1 import java.util.concurrent.TimeUnit;
     2 
     3 /**
     4  * 一个同步方法可以调用另外一个同步方法,一个线程已经拥有了某个对象锁,再次申请仍然会得到这把锁。
     5  * 也就是说synchronized是可重入的。
     6  */
     7 public class SynchronizedTest3 {
     8 
     9     synchronized void m1() {
    10         System.out.println(Thread.currentThread().getName() + " m1 start ...");
    11         try {
    12             TimeUnit.SECONDS.sleep(1);
    13         } catch (InterruptedException e) {
    14             e.printStackTrace();
    15         }
    16         m2();
    17         System.out.println(Thread.currentThread().getName() + " m1 end ...");
    18     }
    19 
    20     synchronized void m2() {
    21         System.out.println(Thread.currentThread().getName() + " m2 start ...");
    22         try {
    23             TimeUnit.SECONDS.sleep(2);
    24         } catch (InterruptedException e) {
    25             e.printStackTrace();
    26         }
    27         System.out.println(Thread.currentThread().getName() + " m2 end ...");
    28     }
    29 
    30     public static void main(String[] args) {
    31 
    32         SynchronizedTest3 test = new SynchronizedTest3();
    33         new Thread(() -> {
    34             test.m1();
    35         }, "t1").start();
    36         new Thread(() -> {
    37             test.m2();
    38         }, "t2").start();
    39 
    40     }
    41 
    42 }

    三、子类同步方法调用父类同步方法,这是可以的。
     1 import java.util.concurrent.TimeUnit;
     2 
     3 /**
     4  * 子类调用父类同步方法,这是可以的
     5  */
     6 public class SynchronizedTest5 {
     7 
     8     public static void main(String[] args) {
     9 
    10         Chinese chinese = new Chinese();
    11         chinese.m();
    12 
    13     }
    14 
    15     static class Person {
    16         synchronized void m() {
    17             System.out.println("m start ...");
    18             try {
    19                 TimeUnit.SECONDS.sleep(2);
    20             } catch (InterruptedException e) {
    21                 e.printStackTrace();
    22             }
    23             System.out.println("m end ...");
    24         }
    25     }
    26 
    27     static class Chinese extends Person {
    28         @Override
    29         synchronized void m() {
    30             System.out.println("child m start ...");
    31             super.m();
    32             System.out.println("child m end ...");
    33         }
    34     }
    35 
    36 }
     
    四、synchronized遇到异常,线程会释放锁。
     1 import java.util.concurrent.TimeUnit;
     2 
     3 /**
     4  * 多线程环境synchronized遇到异常,线程会释放锁
     5  */
     6 public class SynchronizedTest6 {
     7 
     8     int count = 0;
     9 
    10     synchronized void m() {
    11         System.out.println(Thread.currentThread().getName() + " start");
    12         while (true) {
    13             count++;
    14             System.out.println(Thread.currentThread().getName() + " count=" + count);
    15             try {
    16                 TimeUnit.SECONDS.sleep(1);
    17             } catch (InterruptedException e) {
    18                 e.printStackTrace();
    19             }
    20             if(count == 5) {
    21                 int i = 1/0; //此处会抛出异常,锁将被释放,想要锁不被释放,可以在这里进行catch,让循环继续.
    22                 //java.lang.ArithmeticException: / by zero
    23                 //解决办法: try-catch这个异常
    24             }
    25         }
    26     }
    27 
    28     public static void main(String[] args) {
    29 
    30         SynchronizedTest6 test = new SynchronizedTest6();
    31         Runnable r = new Runnable() {
    32             @Override
    33             public void run() {
    34                 test.m();
    35             }
    36         };
    37 
    38         new Thread(r, "线程1").start();
    39 
    40         try {
    41             TimeUnit.SECONDS.sleep(3);
    42         } catch (InterruptedException e) {
    43             e.printStackTrace();
    44         }
    45 
    46         new Thread(r, "线程2").start();
    47 
    48     }
    49 
    50 }
    五、synchronized优化
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.TimeUnit;
    
    /**
     * synchronized优化
     * synchronized代码块包住的代码越少越好
     */
    public class SynchronizedTest7 {
    
        int count = 0;
    
        synchronized void add() {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int i=0; i<1000; i++) {
                count++;
            }
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    
         void add1() {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
             synchronized(this) {
                 for(int i=0; i<1000; i++) {
                     count++;
                 }
             }
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
    
            SynchronizedTest7 test = new SynchronizedTest7();
            List<Thread> threads = new ArrayList<>(10);
            long start = System.currentTimeMillis();
            for(int i=0; i<10; i++) {
                threads.add(new Thread(() -> {
                    test.add();
                }, "Thread" + i));
            }
            threads.forEach(t -> t.start());
            threads.forEach(t -> {
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            long end = System.currentTimeMillis();
            System.out.println("add方法耗时:" + (end - start) + " count=" + test.count);
    
            //add1方法
            threads.clear();
            start = System.currentTimeMillis();
            for(int i=0; i<10; i++) {
                threads.add(new Thread(() -> {
                    test.add1();
                }, "Thread" + i));
            }
            threads.forEach(t -> t.start());
            threads.forEach(t -> {
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            end = System.currentTimeMillis();
            System.out.println("add1方法耗时:" + (end - start) + " count=" + test.count);
    
            ExecutorService service = Executors.newFixedThreadPool(10);
            start = System.currentTimeMillis();
            for(int i=0; i<10; i++) {
                service.submit(() -> {
                    test.add();
                });
            }
            while (true) {
                if(!service.isTerminated()) break;
            }
            end = System.currentTimeMillis();
            System.out.println("ExecutorService add方法耗时:" + (end - start) + " count=" + test.count);
            service.shutdown();
    //        if(service.isTerminated()) {
    //            end = System.currentTimeMillis();
    //            System.out.println("ExecutorService add方法耗时:" + (end - start) + " count=" + test.count);
    //        }
    
            ExecutorService service1 = Executors.newFixedThreadPool(10);
            start = System.currentTimeMillis();
            for(int i=0; i<10; i++) {
                service1.submit(() -> {
                    test.add1();
                });
            }
            while (true) {
                if(!service1.isTerminated()) break;
            }
            end = System.currentTimeMillis();
            System.out.println("ExecutorService add1方法耗时:" + (end - start) + " count=" + test.count);
            service1.shutdown();
    //        if(service1.isTerminated()) {
    //            end = System.currentTimeMillis();
    //            System.out.println("ExecutorService add1方法耗时:" + (end - start) + " count=" + test.count);
    //        }
        }
    
    }
    六、不要以字符串常量作为锁定对象
     1 /**
     2  * 不要以字符串常量作为锁定对象
     3  * str1和str2是同一个都对象
     4  * 会发生诡异的死锁阻塞
     5  */
     6 public class SynchronizedTest9 {
     7 
     8     String str1 = "Hello";
     9     String str2 = "Hello";
    10 
    11     void m1() {
    12         synchronized (str1) {
    13 
    14         }
    15     }
    16 
    17     void m2() {
    18         synchronized (str2) {
    19 
    20         }
    21     }
    22 
    23 }
     
     
    七、synchronized写法
     1 public class SynchronizedTest2 {
     2 
     3     private static int count = 10;
     4 
     5     private synchronized void method() { //等同于synchronized(this)
     6         count--;
     7         System.out.println(Thread.currentThread().getName() + " count=" + count);
     8     }
     9 
    10     private static void method2() {
    11         synchronized (SynchronizedTest2.class) { //考虑一下这里写synchronized(this)是否可以?
    12             count--;
    13         }
    14     }
    15 
    16 }
     
     
  • 相关阅读:
    header
    panel----单个基础版
    vue-demo
    js不同类型变量比较
    reset.css
    关于各个浏览器的兼容问题
    git
    AMD与CMD区别
    喜欢前端的看过来哦
    js中数组去重的几种方法
  • 原文地址:https://www.cnblogs.com/mxh-java/p/12246413.html
Copyright © 2011-2022 走看看