并发库应用之四 & 线程锁Lock应用
Java5的线程并发库中,提供了相应的线程锁接口Lock来帮助我们同步处理。Lock比传统线程模型中的synchronized更加面向对象,锁本身也是一个对象,两个线程执行的代码要实现同步互斥效果,就要使用同一个锁对象。锁要上在要操作的资源类的内部方法中,而不是线程代码中。
java.util.concurrent.locks在并发编程中很常用的实用接口。
|----Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
|----ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作
|----Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待
本篇主要讲解与Lock有关内容,故一下主要针对Lock进行阐述:
接口:
public interface Lock
所有已知实现类:
ReentrantLock
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock
随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用 synchronized 方法和语句时会出现的锁自动释放功能。在大多数情况下,应该使用以下语句:
Lock lk = ...; lk.lock(); try { // access the resource protected by this lock } finally { lk.unlock(); }
锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用 try-finally 或 try-catch 加以保护,以确保在必要时释放锁。
打印字符串使用锁机制进行打印,使其内部线程之间互斥,源代码如下:
1 import java.util.concurrent.ExecutorService; 2 import java.util.concurrent.Executors; 3 import java.util.concurrent.locks.Lock; 4 import java.util.concurrent.locks.ReentrantLock; 5 6 public class LockTest { 7 public static void main(String[] args) { 8 final Business business = new Business(); 9 ExecutorService executor = Executors.newFixedThreadPool(3); 10 for (int i = 0; i < 3; i++) { 11 executor.execute( 12 new Runnable() { 13 public void run() { 14 business.service(); 15 } 16 } 17 18 ); 19 } 20 executor.shutdown(); 21 } 22 23 private static class Business { 24 private int count; 25 Lock lock = new ReentrantLock(); 26 27 public void service() { 28 lock.lock(); 29 try { 30 count++; 31 try { 32 Thread.sleep(1); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 System.out.println(count); 37 } catch (RuntimeException e) { 38 e.printStackTrace(); 39 } finally { 40 lock.unlock(); 41 } 42 } 43 } 44 }
运行结果如下所示:
提示:更加常用且重要的锁为读写锁,具体详情请查看我的下一篇博客:并发库应用之五 & ReadWriteLock场景应用