Java多线程之synchronized关键字
Posted 尘世间迷茫的小书童
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于Java多线程之synchronized关键字的主要内容,如果未能解决你的问题,请参考以下文章
Java多线程系列---“基础篇”04之 synchronized关键字
Java——多线程高并发系列之synchronized关键字
Java——多线程高并发系列之synchronized关键字