Java并发之读写锁Lock和条件阻塞Condition的应用

Java 5中提供了另一种实现线程同步或互斥的机制,即使用LockCondition

Lock比传统线程模型中的synchronized方式更加面向对象,也提供了更多可选择的锁机制。与生活中的锁类似,锁本身也是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须使用同一个Lock对象。锁是上在代表要操作的资源的类的内部方法中,而不是线程代码中。

 

Lock使用示例:

 

复制代码
 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3 
 4 // An example of using Lock.
 5 public class LockTest {
 6 
 7     public static void main(String[] args) {
 8         new LockTest().init();
 9 
10     }
11 
12     private void init() {
13         final Outputer outputer = new Outputer();
14         new Thread(new Runnable() {
15             @Override
16             public void run() {
17                 while (true) {
18                     try {
19                         Thread.sleep(10);
20 
21                     } catch(InterruptedException e) {
22                         e.printStackTrace();
23 
24                     }
25                     outputer.output("aaaaaaaaaaa");
26 
27                 }
28 
29 
30             }
31 
32         }).start();
33 
34         new Thread(new Runnable() {
35             @Override
36             public void run() {
37                 while (true) {
38                     try {
39                         Thread.sleep(10);
40 
41                     } catch(InterruptedException e) {
42                         e.printStackTrace();
43 
44                     }
45                     outputer.output("bbbbbbbbbbb");
46 
47                 }
48 
49 
50             }
51 
52         }).start();
53 
54 
55     }
56 
57     static class Outputer {
58         private Lock lock = new ReentrantLock();
59         public void output(String name) {
60             int len = name.length();
61             lock.lock();
62             try {
63                 for (int i = 0; i < len; i++) {
64                     System.out.print(name.charAt(i));
65 
66                 }
67                 System.out.println();
68 
69             } finally {
70                 lock.unlock();
71 
72             }
73 
74         }
75 
76     }
77 
78 }
复制代码

 

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的,我们只需要上好相应的锁即可。如果代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果代码修改数据,只能有一个人在写,并不能同时读取,那就上写销锁。总之,读的时候上读锁,写的时候上写锁。

Java读写锁示例:

 

复制代码
 1 import java.util.Random;
 2 import java.util.concurrent.locks.ReadWriteLock;
 3 import java.util.concurrent.locks.ReentrantReadWriteLock;
 4  
 5 public class ReadWriteLockTest {
 6     public static void main(String[] args) {
 7         final MyQueue queue = new MyQueue();
 8         for (int i = 0; i < 3; i++) {
 9             new Thread() {
10                 public void run() {
11                     while (true) {
12                         queue.get();
13                     }
14                 }
15  
16             }.start();
17  
18             new Thread() {
19                 public void run() {
20                     while (true) {
21                         queue.put(new Random().nextInt(10000));
22                     }
23                 }
24  
25             }.start();
26         }
27  
28     }
29 }
30  
31 class MyQueue {
32     // 共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
33     private Object data = null; 
34     ReadWriteLock  rwl  = new ReentrantReadWriteLock();
35  
36     public void get() {
37         rwl.readLock().lock();
38         try {
39             System.out.println(Thread.currentThread().getName()
40                     + " be ready to read data!");
41             Thread.sleep((long) (Math.random() * 1000));
42             System.out.println(Thread.currentThread().getName()
43                     + "have read data :" + data);
44         } catch (InterruptedException e) {
45             e.printStackTrace();
46         } finally {
47             rwl.readLock().unlock();
48         }
49     }
50  
51     public void put(Object data) {
52  
53         rwl.writeLock().lock();
54         try {
55             System.out.println(Thread.currentThread().getName()
56                     + " be ready to write data!");
57             Thread.sleep((long) (Math.random() * 1000));
58             this.data = data;
59             System.out.println(Thread.currentThread().getName()
60                     + " have write data: " + data);
61         } catch (InterruptedException e) {
62             e.printStackTrace();
63         } finally {
64             rwl.writeLock().unlock();
65         }
66     }
67     
68 }
复制代码

 

 

 

使用

复制代码
 1 import java.util.HashMap;
 2 import java.util.Map;
 3 import java.util.concurrent.locks.ReadWriteLock;
 4 import java.util.concurrent.locks.ReentrantReadWriteLock;
 5 
 6 // Using a ReadWriteLock to implement a cache.
 7 public class CacheDemo {
 8 
 9     private Map < String,
10     Object > cache = new HashMap < String,
11     Object > ();
12     private ReadWriteLock rwl = new ReentrantReadWriteLock();
13 
14     public static void main(String[] args) {
15         CacheDemo cache = new CacheDemo();
16         Object obj = cache.getData("");
17         System.out.println(obj.toString());
18 
19     }
20 
21     // Get the value from DB if the value does not exist,and then return it.
22     public Object getData(String key) {
23         rwl.readLock().lock();
24         Object value = null;
25         try {
26             value = cache.get(key);
27             if (value == null) {
28                 // Must release read lock before acquiring write lock
29                 rwl.readLock().unlock();
30                 rwl.writeLock().lock();
31                 try {
32                     // Recheck state because another thread might have acquired
33                     // write lock and changed state before we did.
34                     if (value == null) {
35                         // Here may access Database.
36                         // ...
37                         value = "Data";
38 
39                     }
40 
41                 } finally {
42                     rwl.writeLock().unlock();
43 
44                 }
45                 rwl.readLock().lock();
46 
47             }
48 
49         } finally {
50             rwl.readLock().unlock();
51 
52         }
53         return value;
54 
55     }
56 
57 }
复制代码

 

 

 

Condition的功能类似在传统线程技术中的Object.waitObject.notity的功能。在等待Condition时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为Condition应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。

 

一个锁内部可以有多个Condition,即有多路等待和通知,可以参看Jdk1.5提供的LockCondition实现的可阻塞队列的应用案例。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象。

 

JDK文档中提供了一个很不错的示例(http://docs.oracle.com/javase/6/docs/api/ ),用Condition实现一个阻塞队列,代码如下:

 

复制代码
 1 import java.util.concurrent.locks.Condition;
 2 import java.util.concurrent.locks.Lock;
 3 import java.util.concurrent.locks.ReentrantLock;
 4 
 5 public class BoundedBuffer {
 6     final Lock lock = new ReentrantLock();
 7     final Condition notFull = lock.newCondition();
 8     final Condition notEmpty = lock.newCondition();
 9 
10     final Object[] items = new Object[100];
11     int putptr,
12     takeptr,
13     count;
14 
15     public void put(Object x) throws InterruptedException {
16         lock.lock();
17         try {
18             while (count == items.length)
19             notFull.await();
20             items[putptr] = x;
21             if (++putptr == items.length)
22             putptr = 0;
23             ++count;
24             notEmpty.signal();
25 
26         } finally {
27             lock.unlock();
28 
29         }
30 
31     }
32 
33     public Object take() throws InterruptedException {
34         lock.lock();
35         try {
36             while (count == 0)
37             notEmpty.await();
38             Object x = items[takeptr];
39             if (++takeptr == items.length)
40             takeptr = 0;
41             --count;
42             notFull.signal();
43             return x;
44 
45         } finally {
46             lock.unlock();
47 
48         }
49 
50     }
51 
52 }
复制代码

 

你可能感兴趣的:(java,多线程)