• 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 }

    转载:http://blog.sina.com.cn/jiangafu

  • 相关阅读:
    win8 连接到OneDrive时出现问题-感叹号
    让tp6显示详细的错误信息及行号
    TP6出现错误 No input file specified.
    Git 访问慢 解决办法
    mysql5.7当两个字段名类似,查询时会出错
    linux停止进程
    mysql更新数据时:当想mysql某插入有某字段设置了unique且和之前相同时,会报错,并停止运行
    php升级版本后的影响5.5->7.1


  • 原文地址:https://www.cnblogs.com/yaowukonga/p/2658329.html
Copyright © 2020-2023  润新知