JAVA多线程系列--Lock锁-ReentrantLock,ReentrantReadWriteLock应用

1.前言

java除了synchronized 锁外,还有Lock更加灵活的锁。

ReenTrantLock从名字上理解,是可再进入的锁。重入锁是一种递归无阻塞的同步机制,底层实现采用AQS原理实现,具体实现原理将在今后的文章中具体探讨。

ReentrantReadWriterLock:可重入读写锁。读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!ReentrantReadWriterLock的底层实现也是AQS内部状态state同步进行加锁。


2. ReenTrantLock 例子:

/**
 * lock
 * @author niyuelin
 * 
 *
 */
public class ReentrantLockTest {
   public int inc = 0;
   Lock lock = new ReentrantLock();

   public void increase() {
      lock.lock();
      try {
         inc++;
      } finally {
         lock.unlock();
      }
   }

   public static void main(String[] args) {
      final ReentrantLockTest test = new ReentrantLockTest();
      for (int i = 0; i < 10; i++) {
         new Thread() {
            public void run() {
               for (int j = 0; j < 1000; j++)
                  test.increase();
            };
         }.start();
      }
      while (Thread.activeCount() > 2) // 保证前面的线程都执行完
         Thread.yield();
      System.out.println(test.inc);
   }
}

输出:

10000

ReentrantLock必须在使用完后,在finally方法释放,否则别人无法使用该锁,或者重复调用导致死锁。


3.ReentrantReadWriteLock例子

/**
 * ReadWriteLock
 * @author niyuelin
 *
 */
public class ReentrantReadWriteLockTest {
   static class MyObject {
      private Object object;
      private ReadWriteLock lock = new ReentrantReadWriteLock();

      public void get() {
         lock.readLock().lock();
         System.out.println(Thread.currentThread().getName() + "准备读数据!!");
         try {
            Thread.sleep(new Random().nextInt(1000));
            System.out.println(Thread.currentThread().getName() + "读数据为:" + this.object);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            lock.readLock().unlock();
         }
      }

      public void put(Object object) {
         lock.writeLock().lock();
         System.out.println(Thread.currentThread().getName() + "准备写数据");

         try {
            Thread.sleep(new Random().nextInt(1000));
            this.object = object;
            System.out.println(Thread.currentThread().getName() + "写数据为" + this.object);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            lock.writeLock().unlock();
         }
      }
   }

   public static void main(String[] args) throws InterruptedException {
      final MyObject myObject = new MyObject();
      ExecutorService executor = Executors.newCachedThreadPool();

      for (int i = 0; i < 2; i++) {
         executor.execute(new Runnable() {

            @Override
            public void run() {
               for (int j = 0; j < 3; j++)
                  myObject.put(new Random().nextInt(1000));
            }
         });
      }

      for (int i = 0; i < 2; i++) {
         executor.execute(new Runnable() {

            @Override
            public void run() {
               for (int j = 0; j < 3; j++)
                  myObject.get();
            }
         });
      }

      executor.shutdown();
   }
}

输出:

pool-1-thread-2准备写数据
pool-1-thread-2写数据为759
pool-1-thread-2准备写数据
pool-1-thread-2写数据为209
pool-1-thread-1准备写数据
pool-1-thread-1写数据为602
pool-1-thread-1准备写数据
pool-1-thread-1写数据为431
pool-1-thread-4准备读数据!!
pool-1-thread-3准备读数据!!
pool-1-thread-3读数据为:431
pool-1-thread-4读数据为:431
pool-1-thread-2准备写数据
pool-1-thread-2写数据为430
pool-1-thread-1准备写数据
pool-1-thread-1写数据为757
pool-1-thread-3准备读数据!!
pool-1-thread-4准备读数据!!
pool-1-thread-4读数据为:757
pool-1-thread-4准备读数据!!
pool-1-thread-3读数据为:757
pool-1-thread-3准备读数据!!
pool-1-thread-3读数据为:757
pool-1-thread-4读数据为:757


写数据的时候只有一个线程能写,别人不能读。读数据的时候别人不能写,但是可以读


4.总结

ReentrantLock 作为重用锁,在实际开发当中是  synchronized锁的替代方案。

ReentrantReadWriteLock 适合用在对于高并发任务对内存的读写操作时使用。




发布了72 篇原创文章 · 获赞 52 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/niyuelin1990/article/details/78600126