+ ReentrantLock类的使用 
+ ReentrantReadWriteLock类的使用

1. 使用ReentrantLock类

ReentrantLock类能够实现线程之间同步互斥,并且在扩展功能上更加强大,例如嗅探技术多路分支通知等功能,在使用上比synchronized更加灵活。
ReentrantLock类具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。

ReentrantLock实现了Lock接口,该接口包含以下方法:

public interface Lock {

    void lock();

    void lockInterruptibly() throws InterruptedException;

    boolean tryLock();

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    void unlock();

    Condition newCondition();
}

关键字 synchronized 与 wait() 和 notify() / notifyAll() 方法结合可以实现等待/通知模型, ReentrantLock 类也可以实现同样的功能,需要借助 Condition对象。

Condition 对象是JDK1.5中出现的技术,它有更好的灵活性,比如可实现多路通知功能,也就是在一个 Lock 对象里面可以创建多个 Condition (即对象监视器)实例,线程对象可以注册在指定的 Condition 中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。

使用 notify() / notifyAll() 方法进行通知时,被通知的线程由JVM随机选择。通过 ReentrantLock 结合 Condition 可以实现选择性通知

synchronized 相当于整个 Lock 对象中只有一个单一的 Condition 对象,所有的线程都注册在它一个对象的身上。线程 notifyAll() 时,需要通知所有的 WAITING 线程,没有选择权。

Object 类中的 wait() 方法相当于 Condition 类中的 await() 方法。

Object 类中的 wait(long timeout) 方法相当于 Condition 类中的 await(long time,TimeUnit unit) 方法。

Object 类中的 notify() 方法相当于 Condition 类中的 signal() 方法。

Object 类中的 notifyAll() 方法相当于 Condition 类中的 signalAll() 方法。

公平锁与非公平锁

Lock 分为公平锁非公平锁公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的 FIFO先进先出顺序。非公平锁是一种获取锁的抢占机制,是随机获得锁的。

Lock方法

  1. 方法 int getHoldCount() 的作用是查询当前线程保持此锁定的个数,也就是调用 lock()方法的次数。
  2. 方法 int getQueueLength() 的作用是返回正在等待获取此锁定的线程估计数
  3. 方法 int getWaitQueueLength(Condition condition) 的作用是返回等待与此锁定相关的给定条件 Condition 的线程估计数。比如有5个线程,每个线程都执行了同一个 condition 对象的 await() 方法,则调用 getWaitQueueLength(condition) 方法返回的指为5.
  4. 方法 boolean hasQueuedThread(Thread thread) 的作用是查询指定的线程是否正在等待获取此锁定。
  5. 方法 boolean hasQueuedThreads() 的作用是差选是否有线程正在等待获取此锁定。
  6. 方法 boolean hasWaiters(Condition condition) 的作用是查询是否有线程正在等待与此锁定有关的 condition 条件。
  7. 方法 boolean isFair() 的作用是判断是不是公平锁。
  8. 方法 boolean isHeldByCurrentThread() 的作用是查询当前线程是否保持此锁定。
  9. 方法 boolean isLocked() 的作用是查询此锁定是否由任意线程保持。
  10. 方法 void lockInterruptibly() 的作用是:如果当前线程未被中断,则获取锁定;如果已经被中断则抛出异常( java.lang.InterruptedException ).
  11. 方法 boolean tryLock() 的作用是:仅在调用时锁未被另外线程保持的情况下,才获取此锁定。
  12. 方法 boolean tryLock(long timeout,TimeUnit unit) 的作用是:如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。

使用Condition对象可以对线程执行的业务进行排序规划

2. 使用ReentrantReadWriteLock类

读写锁有两个锁:一个是读操作相关的锁,也称为共享锁;一个是写操作相关的锁,也称为排他锁

多个读锁之间不互斥;读锁与写锁互斥;写锁与写锁互斥。

package com.zxd.concurrent.learning;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* @author CoderZZ
* @Title: ${FILE_NAME}
* @Project: ConcurrentLearning
* @Package com.zxd.concurrent.learning
* @description: 读锁不互斥;读写、写写互斥
* @Version 1.0
* @create 2018-04-08 21:29
**/
public class ReentrantReadWriteLockTest { private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); public void read(){
try {
reentrantReadWriteLock.readLock().lock();
System.out.println("获得读锁"+Thread.currentThread().getName()+" timestamp:"+System.currentTimeMillis());
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
reentrantReadWriteLock.readLock().unlock();
}
} public void write(){
try{
reentrantReadWriteLock.writeLock().lock();
System.out.println("获得写锁"+Thread.currentThread().getName()+" timestamp:"+System.currentTimeMillis());
Thread.sleep(10000);
}catch (Exception e){
e.printStackTrace();
}finally {
reentrantReadWriteLock.writeLock().unlock();
}
} public static void main(String[] args){
ReentrantReadWriteLockTest reentrantReadWriteLockTest = new ReentrantReadWriteLockTest();
Runnable readRunnable = new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.read();
}
};
Thread threadA = new Thread(readRunnable);
threadA.setName("A");
threadA.start();
Thread threadB = new Thread(readRunnable);
threadB.setName("B");
threadB.start();
Runnable writeRunnable = new Runnable() {
@Override
public void run() {
reentrantReadWriteLockTest.write();
}
};
Thread writeA = new Thread(writeRunnable);
writeA.setName("writeA");
writeA.start();
Thread writeB = new Thread(writeRunnable);
writeB.setName("writeB");
writeB.start();
}
}

运行结果如下:

最新文章

  1. 为什么要在游戏开发中使用ECS模式
  2. MineCraft note
  3. ---awk 调shell 命令的方法
  4. Maven 库
  5. sqlserver中对时间类型的字段转换
  6. .Net下 自动执行MSI和EXE文件
  7. iOS - 视频循环播放
  8. PHP开发框架--CodeIgniter(CI)使用总结
  9. 图解 CSS: 理解样式表的逻辑(转载)
  10. C#.Net网页加载等待效果漂亮并且简单
  11. bzoj 1010 [HNOI2008]玩具装箱toy(DP的斜率优化)
  12. 网页嵌入WMP代码(转)
  13. diff命令
  14. Centos下配置tomcat7的https证书
  15. wordpress网站迁移
  16. copy from insert using 语句迁移数据
  17. 推举算法 AdaBoost 哥德尔奖 Godel Prize
  18. boost 编写finger服务
  19. postfix配置spf认证和dkim认证
  20. 关于mybatis map foreach遍历

热门文章

  1. [心得]暑假Day 8
  2. orale数据库的SQL查询
  3. TCP层sendmsg系统调用的实现分析
  4. fastadmin后台视频文件上传,受限制,修改php.ini配置即可
  5. uboot下如何读写rtc pcf2127的寄存器?
  6. TensorFlow 学习(6)———TensorFlow运作方式
  7. LC 841. Keys and Rooms
  8. vue路由在keep-alive下的刷新问题 对watch的影响
  9. java代码实现将集合中的重复元素去掉
  10. 动态执行文本vba代码