Java多线程编程核心技术---Lock的基本概念和使用
Lock接口:
ReentrantLock的基本功能:
ReentrantLock的lock和unlock方法进行加锁,解锁。可以起到和synchronized关键字一样的效果;
选择性通知!!!:
使用Condition实现等待通知,和wait/notifyAll机制一样,要使用await()方法进入WAITING状态,就必须要先使用lock.lock()获得同步监视器。
1 package service; 2 3 import java.util.concurrent.locks.Condition; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 public class MyService { 7 private ReentrantLock lock = new ReentrantLock(); 8 private Condition condition = lock.newCondition(); 9 10 public void waitMethod() { 11 try { 12 lock.lock(); 13 System.out.println("A"); 14 condition.await(); 15 System.out.println("B"); 16 } catch (InterruptedException e) { 17 e.printStackTrace(); 18 } finally { 19 lock.unlock(); 20 System.out.println("锁释放了!"); 21 } 22 } 23 }
类比wait/notify机制:wait-->await notify-->signal notifyAll-->signalAll
选择性通知:使用多个Condition实现
package service; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyService { private Lock lock = new ReentrantLock(); // 使用多个Condition todo 查看原理 public Condition conditionA = lock.newCondition(); public Condition conditionB = lock.newCondition(); public void awaitA() { try { lock.lock(); System.out.println("begin awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionA.await(); System.out.println(" end awaitA时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void awaitB() { try { lock.lock(); System.out.println("begin awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionB.await(); System.out.println(" end awaitB时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void signalAll_A() { try { lock.lock(); System.out.println(" signalAll_A时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionA.signalAll(); } finally { lock.unlock(); } } public void signalAll_B() { try { lock.lock(); System.out.println(" signalAll_B时间为" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName()); conditionB.signalAll(); } finally { lock.unlock(); } } }
public ReentrantLock(true) 采用公平策略。反之采用不公平策略。
tryLock():如果没被锁定,获得锁。否则不获得锁。
tryLock(long timeout , TimeUnit unit):给宽定时间的tryLock()
1 package service; 2 3 import java.util.concurrent.locks.ReentrantLock; 4 5 public class MyService { 6 7 public ReentrantLock lock = new ReentrantLock(); 8 9 public void waitMethod() { 10 if (lock.tryLock()) { 11 System.out.println(Thread.currentThread().getName() + "获得锁"); 12 } else { 13 System.out.println(Thread.currentThread().getName() + "没有获得锁"); 14 } 15 } 16 }
1 package service; 2 3 import java.util.concurrent.TimeUnit; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 public class MyService { 7 8 public ReentrantLock lock = new ReentrantLock(); 9 10 public void waitMethod() { 11 try { 12 if (lock.tryLock(3, TimeUnit.SECONDS)) { 13 System.out.println(" " + Thread.currentThread().getName() 14 + "获得锁的时间:" + System.currentTimeMillis()); 15 Thread.sleep(10000); 16 } else { 17 System.out.println(" " + Thread.currentThread().getName() 18 + "没有获得锁"); 19 } 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } finally { 23 if (lock.isHeldByCurrentThread()) { 24 lock.unlock(); 25 } 26 } 27 } 28 }
使用Codition实现顺序执行
1 package test.run; 2 3 import java.util.concurrent.locks.Condition; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 public class Run { 7 8 volatile private static int nextPrintWho = 1; 9 private static ReentrantLock lock = new ReentrantLock(); 10 final private static Condition conditionA = lock.newCondition(); 11 final private static Condition conditionB = lock.newCondition(); 12 final private static Condition conditionC = lock.newCondition(); 13 14 public static void main(String[] args) { 15 16 Thread threadA = new Thread() { 17 public void run() { 18 try { 19 lock.lock(); 20 while (nextPrintWho != 1) { 21 conditionA.await(); 22 } 23 for (int i = 0; i < 3; i++) { 24 System.out.println("ThreadA " + (i + 1)); 25 } 26 nextPrintWho = 2; 27 conditionB.signalAll(); 28 } catch (InterruptedException e) { 29 e.printStackTrace(); 30 } finally { 31 lock.unlock(); 32 } 33 } 34 }; 35 36 Thread threadB = new Thread() { 37 public void run() { 38 try { 39 lock.lock(); 40 while (nextPrintWho != 2) { 41 conditionB.await(); 42 } 43 for (int i = 0; i < 3; i++) { 44 System.out.println("ThreadB " + (i + 1)); 45 } 46 nextPrintWho = 3; 47 conditionC.signalAll(); 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 } finally { 51 lock.unlock(); 52 } 53 } 54 }; 55 56 Thread threadC = new Thread() { 57 public void run() { 58 try { 59 lock.lock(); 60 while (nextPrintWho != 3) { 61 conditionC.await(); 62 } 63 for (int i = 0; i < 3; i++) { 64 System.out.println("ThreadC " + (i + 1)); 65 } 66 nextPrintWho = 1; 67 conditionA.signalAll(); 68 } catch (InterruptedException e) { 69 e.printStackTrace(); 70 } finally { 71 lock.unlock(); 72 } 73 } 74 }; 75 Thread[] aArray = new Thread[5]; 76 Thread[] bArray = new Thread[5]; 77 Thread[] cArray = new Thread[5]; 78 79 for (int i = 0; i < 5; i++) { 80 aArray[i] = new Thread(threadA); 81 bArray[i] = new Thread(threadB); 82 cArray[i] = new Thread(threadC); 83 84 aArray[i].start(); 85 bArray[i].start(); 86 cArray[i].start(); 87 } 88 89 } 90 }
ReentrantReadWriteLock:
出现目的:ReentrantLock完全互斥排他,效率低下。
改善:ReentrantReadWriteLock 读写锁。只要有写操作就是互斥的,没有写操作,就是共享的。
1 package service; 2 3 import java.util.concurrent.locks.ReentrantReadWriteLock; 4 5 6 /* 7 output:时间差为10000 8 9 */ 10 11 public class Service { 12 13 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 14 15 public void read() { 16 try { 17 try { 18 lock.readLock().lock(); 19 System.out.println("获得读锁" + Thread.currentThread().getName() 20 + " " + System.currentTimeMillis()); 21 Thread.sleep(10000); 22 } finally { 23 lock.readLock().unlock(); 24 } 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 } 29 30 public void write() { 31 try { 32 try { 33 lock.writeLock().lock(); 34 System.out.println("获得写锁" + Thread.currentThread().getName() 35 + " " + System.currentTimeMillis()); 36 Thread.sleep(10000); 37 } finally { 38 lock.writeLock().unlock(); 39 } 40 } catch (InterruptedException e) { 41 e.printStackTrace(); 42 } 43 } 44 45 }