内置锁(隐式锁)和显示锁

来源:互联网 发布:java之父 编辑:程序博客网 时间:2024/05/22 13:38

1.内置锁:
(1)原理:通过内部的一个叫做监视器锁的原理来实现的,但是监视器锁本质又是依赖于底层的操作系统的Mutes Lock来实现的,操作系统之间实现线程的切换需要从用户态转换到核心态,这个成本非常高,状态之间转换需要很长的时间,所以内置锁效率较低。

(2)如何加锁和释放锁
锁对象越小越好
内置锁获得锁和释放锁是隐式的,进入synchronized修饰的代码块就获得锁,走出就释放锁
(3)通信
wait(),notify()
wait()会立刻释放当前的锁,并进入等待状态,等待到相应的notify并重新获得锁过后才能继续执行;notify()不会立刻释放锁,必须要等待notify所在线程执行完synchronized块中的所有代码才会释放
(4)编码
模式较为简单,不必显式的加锁释放锁
(5)灵活性
一旦进入等待状态没既不能中断也不能取消,容易产生饥饿和死锁的问题
在线程调用notify方法时,会随机选择相应的对象的等待队列的一个线程将其唤醒,而不是按照FIFO(先入先出队列)。
(6)性能
与显示锁相效率较低,但是java6以后性能差别不大
2.显式锁
参考原文:http://blog.csdn.net/ghsau/article/details/7461369/
在一些内置锁无法满足需求的情况下,显式锁可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时,可轮询,可中断,公平队列,及非块结构的锁。否则还是应该优先使用synchronized。
读写锁: ReadWriteLock

class Data {          private int data;// 共享数据      private ReadWriteLock rwl = new ReentrantReadWriteLock();         public void set(int data) {          rwl.writeLock().lock();// 取到写锁          try {              System.out.println(Thread.currentThread().getName() + "准备写入数据");              try {                  Thread.sleep(20);              } catch (InterruptedException e) {                  e.printStackTrace();              }              this.data = data;              System.out.println(Thread.currentThread().getName() + "写入" + this.data);          } finally {              rwl.writeLock().unlock();// 释放写锁          }      }         public void get() {          rwl.readLock().lock();// 取到读锁          try {              System.out.println(Thread.currentThread().getName() + "准备读取数据");              try {                  Thread.sleep(20);              } catch (InterruptedException e) {                  e.printStackTrace();              }              System.out.println(Thread.currentThread().getName() + "读取" + this.data);          } finally {              rwl.readLock().unlock();// 释放读锁          }      }  }  public static void main(String[] args) {         final Data data = new Data();              for (int i = 0; i < 3; i++) {                  new Thread(new Runnable() {                      public void run() {                          for (int j = 0; j < 5; j++) {                              data.set(new Random().nextInt(30));                          }                      }                  }).start();              }                     for (int i = 0; i < 3; i++) {                  new Thread(new Runnable() {                      public void run() {                          for (int j = 0; j < 5; j++) {                              data.get();                          }                      }                  }).start();              }          }