去故就新Java线程新同步机制

  1、可重入锁ReentrantLock,相当于synchronized块,为临界区提供互斥访问机制。

  (1)相关的接口

  创建一个可重入锁

  Locklock=newReentrantLock();

  请求锁,如果锁被当前另一个线程持有,则阻塞。

  voidlock();

  释放锁

  voidunlock();

  非阻塞型lock()

  booleantryLock();

  (2)使用基本结构

  locker.lock();try{//codeheretoaccessthecirticalsection}finally{locker.unlock();}

  这种结构保证在任何时刻只有一个线程能够进入临界区,如果一个线程锁住了锁对象,其他任何线程在调用lock时,都会被阻塞,直到第一个线程释放锁对象。而且无论try块是否抛出异常,都会执行finally block,解锁locker。

  (3)锁的可重入性

  锁是可重入的,线程能够重复地获取它已经拥有的锁。锁对象维护一个持有计数(hold count)来追踪对lock方法的嵌套调用。线程在每次调用lock后都要调用unlock来释放锁。由于这个特性,被一个锁保护的代码可以调用另一个使用相同锁的方法。

  (4)示例代码:

  importncurrent.locks.Lock;importncurrent.locks.ReentrantLock;classWorkerOneextendsThread{privateLocklocker;publicWorkerOne(Locklocker){this.locker=locker;}publicvoidrun(){locker.lock();try{System.out.println(Thread.currentThread().getName()+”:stepintocriticalsection”);}finally{locker.unlock();}}}classWorkerTwoextendsThread{privateLocklocker;publicWorkerTwo(Locklocker){this.locker=locker;}publicvoidsayHello(){locker.lock();try{System.out.println(Thread.currentThread().getName()+”:callsayHello()”);Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}finally{locker.unlock();}}publicvoidrun(){locker.lock();try{System.out.println(Thread.currentThread().getName()+”:setpintocriticalsection”);//测试锁的可重入性sayHello();}finally{locker.unlock();}}}publicclassTest5{publicstaticvoidmain(String[]args){Locklocker=newReentrantLock();WorkerOnewo=newWorkerOne(locker);wo.setName(“WorkerOne”);WorkerTwowt=newWorkerTwo(locker);wt.setName(“WorkerTwo”);wt.start();wo.start();}}

  输出:

  WorkerTwo:setp into critical sectionWorkerTwo:call sayHello()WorkerOne:step into critical section

  2、条件对象Condition,相当于wait-notify机制,提供一种线程间的等待通知机制,condition中的等待-通知方法是await(),signal(),signalAll(),也需要在互斥环境下被调用。

  (1)相关的接口

  创建Condition对象,Condition对象是跟Lock关联在一起的。

  Locklocker=newReentrantLock(); Conditioncond=locker.newCondition();

  把此线程放到条件的等待集中。

  voidawait();

  解除此条件的等待集中所有线程的阻塞状态。

  voidsignalAll();

  在此条件的等待集中随机选择一个线程,解除其阻塞状态。

  voidsignal();

  (2)使用的基本结构:

  //初始时ok_to_proceed为false. locker.lock() try{ while(!ok_to_proceed){ //进入等待此条件集中,被阻塞,它维持状态直到另一个线程调用同一个条件上的。 //signalAll/signal方法时为止。 cond.await(); } }finally{ cker.unlock(); }

  locker.lock(); try{ //调用将解除所有等待此条件下的线程的阻塞状态。当线程从等待集中被移走时,它们将再次成为可运行的,调度器将再次激活它们 //此时,它们将试图重新进入对象。一旦锁可获得,它们中的某个线程将从await调用返回,从而获得锁并从它被阻塞的地方继续执行。 ok_to_proceed=true; cond.signalAll()orcond.signal(); }finally{ locker.unlock(); }

  ok_to_proceed也是为了防止wait-notify出现的问题,即再wait之间,notify()已经给出通知,此时wait只会一直等待下去,这样就保证了signal()线程的通知被await()线程接收到。

  (3)测试代码:

  importncurrent.locks.Condition; importncurrent.locks.Lock; importncurrent.locks.ReentrantLock; classGlobalV{ publicfinalstaticLocklocker=newReentrantLock(); publicfinalstaticConditioncond=locker.newCondition(); publicstaticbooleanto_proceed=false; } classResponseextendsThread{ publicvoidrun(){ while(true){ GlobalV.locker.lock(); try{ while(!GlobalV.to_proceed){ nd.await(); } System.out.println(“Response:finishajob”); GlobalV.to_proceed=false; }catch(Exceptione){ e.printStackTrace(); }finally{ GlobalV.locker.unlock(); } } } } classRequestextendsThread{ publicvoidrun(){ while(true){ GlobalV.locker.lock(); try{ GlobalV.to_proceed=true; nd.signalAll(); System.out.println(“Request:sendajobtoResponse”); }finally{ GlobalV.locker.unlock(); } try{ Thread.sleep(2000); }catch(InterruptedExceptione){ e.printStackTrace(); } } } } publicclassTest6{ publicstaticvoidmain(String[]args){ Requestreq=newRequest(); Responseres=newResponse(); req.start(); res.start(); } }

  输出:

  Request:send a job to ResponseResponse:finish a jobRequest:send a job to ResponseResponse:finish a jobRequest:send a job to ResponseResponse:finish a jobRequest:send a job to ResponseResponse:finish a job

  3、读写锁ReentrantReadWriteLock,适用于“读多写少”的多线程应用场景,“读-写”互斥,“写-写”互斥,而读-读可以共享同读锁,即一个线程获取读锁,其它线程可直接进入读,不会被阻塞。

  (1)相关接口

  创建读写锁对象

  ReentrantReadWriteLockrwLock=newReentrantReadWriteLock();

  获取读锁

  LockreadLock=rwLock.readLock();

  获取写锁

  LockwriteLock=rwLock.writeLock();

  (2)读写锁使用基本结构

  //对所有的读操作添加读锁 readLock.lock(); try{ //codetoread }finally{ readLock.unlock(); }

  //对所有的写操作添加写锁 writeLock.lock(); try{ //codetowrite }finally{ writeLock.unlock(); }

  (3)测试代码:

  importncurrent.locks.Lock; importncurrent.locks.ReentrantReadWriteLock; classReaderextendsThread{ privateLockreadLock=null; publicReader(LockreadLock){ this.readLock=readLock; } publicvoidrun(){ while(true){ readLock.lock(); try{ System.out.println(Thread.currentThread().getName() +”:readactionfor1seconds-“+ReadWriteLock.testVal); }finally{ readLock.unlock(); } try{ Thread.sleep(1000); }catch(InterruptedExceptione){ e.printStackTrace(); } } } } classWriterextendsThread{ privateLockwriteLock=null; publicWriter(LockwriteLock){ this.writeLock=writeLock; } publicvoidrun(){ while(true){ writeLock.lock(); try{ System.out.println(Thread.currentThread().getName() +”:writeactionfor2seconds”); if(ReadWriteLock.testVal.equals(“1111″)) ReadWriteLock.testVal=”2222″; else ReadWriteLock.testVal=”1111″; }finally{ writeLock.unlock(); } try{ Thread.sleep(2000); }catch(InterruptedExceptione){ e.printStackTrace(); } } } } publicclassReadWriteLock{ publicstaticStringtestVal=”Initiation”; publicstaticvoidmain(String[]args){ ReentrantReadWriteLocklock=newReentrantReadWriteLock(); LockreadLock=lock.readLock(); LockwriteLock=lock.writeLock(); Readerreader1=newReader(readLock); reader1.setName(“reader1”); Readerreader2=newReader(readLock); reader2.setName(“reader2”); Readerreader3=newReader(readLock); reader3.setName(“reader3”); Readerreader4=newReader(readLock); reader4.setName(“reader4”); Writerwriter=newWriter(writeLock); writer.setName(“writer1”); reader1.start(); reader2.start(); reader3.start(); reader4.start(); writer.start(); } }

  输出:

  reader1:read action for 1 seconds-Initiationreader3:read action for 1 seconds-Initiationwriter1:write action for 2 secondsreader2:read action for 1 seconds-1111reader4:read action for 1 seconds-1111reader3:read action for 1 seconds-1111reader1:read action for 1 seconds-1111reader4:read action for 1 seconds-1111reader2:read action for 1 seconds-1111writer1:write action for 2 secondsreader4:read action for 1 seconds-2222reader1:read action for 1 seconds-2222reader3:read action for 1 seconds-2222reader2:read action for 1 seconds-2222

  4、总结

  Lock接口替代synchronized

  Lock接口可以比sychronized提供更广泛的锁定操作,可以提供多把不同的锁,且锁之间互不干涉。

  Lock接口提供lock()与unlock()方法,使用明确调用来完成同步的,OO思想好于前者。

  Lock可以自由操控同步范围(scope)。

  Lock接口支持nested lock(嵌套锁定),并提供了丰富的api。

  Lock接口提供了tryLock()方法,支持尝试取得某个object lock。

就是去旅行。牵着彼此的手,

去故就新Java线程新同步机制

相关文章:

你感兴趣的文章:

标签云: