1.概念
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。
2.案例
package org.lkl.thread; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockFoo { /** * 两个线程打印姓名 */ public static void main(String[] args) { final Outputter out = new Outputter() ; new Thread(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep(200) ; out.print("zhangsan") ; } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); new Thread(new Runnable() { @Override public void run() { while(true){ try { Thread.sleep(1000) ; out.print("liaokailinliaokailinliaokailinliaokailinliaokailinliaokailin") ; } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } class Outputter{ Lock lock = new ReentrantLock() ; public void print(String name){ lock.lock() ; //加上锁 只有等到操作全完成以后才释放锁 try { if(name!=null){ for(int i = 0 ; i<name.length() ;i++){ System.out.print(name.charAt(i)); } System.out.println(); } }finally { lock.unlock() ;//解锁 一般都在finally中解锁 不过程序是否有异常 最终都要解锁 否则会导致阻塞 } } }
3. 读写锁
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;
如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
package cn.itcast.heima2; import java.util.Random; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockTest { public static void main(String[] args) { final Queue3 q3 = new Queue3(); for(int i=0;i<3;i++) { new Thread(){ public void run(){ while(true){ q3.get(); } } }.start(); new Thread(){ public void run(){ while(true){ q3.put(new Random().nextInt(10000)); } } }.start(); } } } class Queue3{ private Object data = null;//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。 ReadWriteLock rwl = new ReentrantReadWriteLock(); public void get(){ rwl.readLock().lock(); try { System.out.println(Thread.currentThread().getName() + " be ready to read data!"); Thread.sleep((long)(Math.random()*1000)); System.out.println(Thread.currentThread().getName() + "have read data :" + data); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.readLock().unlock(); } } public void put(Object data){ rwl.writeLock().lock(); try { System.out.println(Thread.currentThread().getName() + " be ready to write data!"); Thread.sleep((long)(Math.random()*1000)); this.data = data; System.out.println(Thread.currentThread().getName() + " have write data: " + data); } catch (InterruptedException e) { e.printStackTrace(); }finally{ rwl.writeLock().unlock(); } } }
4. Condition
package org.lkl.thead.foo01; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ConditionFoo { /** * 子线程先执行10次 然后主线程再执行20次 如此循环50次 */ public static void main(String[] args) { final Business b = new Business() ; //子线程执行50次 for(int i = 1 ;i<=50 ;i++){ final int seq = i ; new Thread(new Runnable() { public void run() { b.sub(seq) ; } }).start() ; } //主线程执行50次 for(int i = 1 ;i<=50 ;i++){ b.main(i) ; } } } class Business{ boolean isSub = true ; Lock lock = new ReentrantLock() ; Condition condition = lock.newCondition() ; //子线程执行10次 public void sub(int j ){ //加lock以后不需要synchronized lock.lock() ; try { while(!isSub){ try { condition.await() ; } catch (InterruptedException e) { e.printStackTrace(); } } for(int i = 1 ;i<=10 ;i++){ System.out.println("sub thread execute times " + i + " loop of "+ j); } isSub = false ; condition.signalAll() ; } finally { lock.unlock() ; } } //主线程执行20次 public void main(int j ){ lock.lock() ; try { while(isSub){ try { condition.await() ; } catch (InterruptedException e) { e.printStackTrace(); } } for(int i = 1 ;i<=20 ;i++){ System.out.println("main thread execute times " + i + " loop of "+ j); } isSub = true ; // condition.signal() ; condition.signalAll() ; }finally { lock.unlock() ; } } }
5. 通过condition实现三个线程之间的通信
package cn.itcast.heima2; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ThreeConditionCommunication { /** * @param args */ public static void main(String[] args) { final Business business = new Business(); new Thread( new Runnable() { @Override public void run() { for(int i=1;i<=50;i++){ business.sub2(i); } } } ).start(); new Thread( new Runnable() { @Override public void run() { for(int i=1;i<=50;i++){ business.sub3(i); } } } ).start(); for(int i=1;i<=50;i++){ business.main(i); } } static class Business { Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); private int shouldSub = 1; public void sub2(int i){ lock.lock(); try{ while(shouldSub != 2){ try { condition2.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=10;j++){ System.out.println("sub2 thread sequence of " + j + ",loop of " + i); } shouldSub = 3; condition3.signal(); }finally{ lock.unlock(); } } public void sub3(int i){ lock.lock(); try{ while(shouldSub != 3){ try { condition3.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=20;j++){ System.out.println("sub3 thread sequence of " + j + ",loop of " + i); } shouldSub = 1; condition1.signal(); }finally{ lock.unlock(); } } public void main(int i){ lock.lock(); try{ while(shouldSub != 1){ try { condition1.await(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } for(int j=1;j<=100;j++){ System.out.println("main thread sequence of " + j + ",loop of " + i); } shouldSub = 2; condition2.signal(); }finally{ lock.unlock(); } } } }