多线程基础回顾(二)-同步锁
线程同步方式
启动3个线程,目的打印出“abcabcabc”字样。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Add implements Runnable{ 2 private static char[] arr={'a','b','c'}; 3 @Override 4 public void run() { 5 for(int i=0;i<arr.length;i++){ 6 System.out.print(arr[i]); 7 } 8 } 9 } 10 public class ThreadTest{ 11 public static void main(String[] args) { 12 Add add = new Add(); 13 new Thread(add).start(); 14 new Thread(add).start(); 15 new Thread(add).start(); 16 } 17 }
上边的代码是无法实现想要的结果,需要加入线程同步才行。
一、使用synchronized关键字
将上边的runable稍作修改
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Add implements Runnable{ 2 private static char[] arr={'a','b','c'}; 3 @Override 4 public void run() { 5 synchronized (this) { 6 for(int i=0;i<arr.length;i++){ 7 System.out.print(arr[i]); 8 } 9 } 10 } 11 }
这里this指实例本身,相当于实例方法同步。
1.实例方法同步:synchronized void method(){}
指同步在拥有该方法的对象上(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法。
2. 静态方法同步:synchronized static void method(){}
指同步在该方法所在的类对象上,它可以对类的所有对象实例起作用。
3. 实例方法中的同步块:synchronized(this){/区块/}
表示只对这个区块的资源实行互斥访问,括号内为监视器,(这里this为调用该方法的实例作为监视器,执行时和同步方法一样。)最简单的监听器:byte by = new byte[0];
4. synchronized关键字是不能继承的,
也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。
二、使用Lock
ReentrantLock 重入锁:
- 可重入、互斥、实现了Lock接口的锁,功能同synchronized,更加灵活。
- 需手动释放锁,一般使用try...finally,防止异常死锁。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Add implements Runnable{ 2 private Lock lock = new ReentrantLock(); 3 private static char[] arr={'a','b','c'}; 4 @Override 5 public void run() { 6 lock.lock();//获取锁 7 try{ 8 for(int i=0;i<arr.length;i++){ 9 System.out.print(arr[i]); 10 } 11 }catch(Expetion e){ 12 //捕获操作 13 }finally{ 14 lock.unlock();//手动释放锁 15 } 16 17 } 18 }
ReentrantReadWriteLock 读写锁,
- 读锁与写锁互斥。
- 读锁共享,可被多条线程同时占有。
- 写锁与读锁,写锁互斥,只能被一条线程占有。
- 锁降级:获取写锁,再获取读锁,再释放写锁,则降级为读锁。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class readAndWrite{ 2 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 3 private final Lock rl = lock.readLock(); 4 private final Lock wl = lock.writeLock(); 5 StringBuilder sb = new StringBuilder("start:"); 6 public void read(){ 7 String name = Thread.currentThread().getName(); 8 if(lock.isWriteLocked()){ 9 System.out.println(name+":写锁被占有,无法获取读锁"); 10 }else{ 11 try{ 12 rl.lock(); 13 System.out.println(name+":得到读锁"); 14 Thread.sleep(1000); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 }finally{ 18 System.out.println(name+":释放读锁"); 19 rl.unlock(); 20 } 21 } 22 } 23 public void write(){ 24 String name = Thread.currentThread().getName(); 25 try{ 26 wl.lock(); 27 System.out.println(name+":获取到写锁"); 28 sb.append(name+","); 29 }finally{ 30 wl.unlock(); 31 System.out.println(name+":释放写锁"); 32 } 33 } 34 } 35 //测试 36 public class ThreadTest{ 37 public static void main(String[] args) { 38 readAndWrite wr = new readAndWrite(); 39 ExecutorService ser1 = Executors.newFixedThreadPool(3); 40 ExecutorService ser2 = Executors.newFixedThreadPool(3); 41 for(int i=0;i<5;i++){ 42 ser1.execute(new Runnable() { 43 @Override 44 public void run() { 45 wr.write(); 46 } 47 }); 48 ser2.execute(new Runnable() { 49 @Override 50 public void run() { 51 wr.read(); 52 } 53 }); 54 } 55 ser1.shutdown(); 56 ser2.shutdown(); 57 System.out.println("执行关闭线程池,sb="+wr.sb.toString()); 58 try { 59 while(!ser1.awaitTermination(1000, TimeUnit.MILLISECONDS)) { 60 System.out.println("等待线程池关闭"); 61 } 62 System.out.println("线程池关闭,sb="+wr.sb.toString()); 63 } catch (InterruptedException e) { 64 e.printStackTrace(); 65 } 66 67 } 68 }
上边测试代码执行结果
pool-1-thread-1:获取到写锁
pool-1-thread-1:释放写锁
pool-2-thread-1:得到读锁
执行关闭线程池,sb=start:pool-1-thread-1,
pool-2-thread-1:释放读锁
pool-1-thread-2:获取到写锁
pool-1-thread-2:释放写锁
pool-2-thread-2:得到读锁
等待线程池关闭
pool-2-thread-2:释放读锁
pool-1-thread-3:获取到写锁
pool-1-thread-3:释放写锁
pool-2-thread-3:得到读锁
pool-2-thread-2:写锁被占有,无法获取读锁
等待线程池关闭
pool-2-thread-3:释放读锁
pool-1-thread-1:获取到写锁
pool-1-thread-1:释放写锁
pool-2-thread-1:得到读锁
等待线程池关闭
pool-2-thread-1:释放读锁
pool-1-thread-2:获取到写锁
pool-1-thread-2:释放写锁
等待线程池关闭
线程池关闭,sb=start:pool-1-thread-1,pool-1-thread-2,pool-1-thread-3,pool-1-thread-1,pool-1-thread-2,