ReentrantLock简介

  Reentrantlock是一个可重入的互斥锁,又被称为独占锁。

  Reentrantlock:分为公平锁和非公平锁,它们的区别体现在获取锁的机制上是否公平。“锁”是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock在同一个时间点只能被一个线程获取(当某线程获取到“锁”时,其它线程就必须等待);ReentraantLock是通过一个FIFO的等待队列来管理获取该锁所有线程的。在“公平锁”的机制下,线程依次排队获取锁;而“非公平锁”在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁。

// 创建一个 ReentrantLock ,默认是“非公平锁”。
ReentrantLock()
// 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair) // 查询当前线程保持此锁的次数。
int getHoldCount()
// 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
protected Thread getOwner()
// 返回一个 collection,它包含可能正等待获取此锁的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正等待获取此锁的线程估计数。
int getQueueLength()
// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回等待与此锁相关的给定条件的线程估计数。
int getWaitQueueLength(Condition condition)
// 查询给定线程是否正在等待获取此锁。
boolean hasQueuedThread(Thread thread)
// 查询是否有些线程正在等待获取此锁。
boolean hasQueuedThreads()
// 查询是否有些线程正在等待与此锁有关的给定条件。
boolean hasWaiters(Condition condition)
// 如果是“公平锁”返回true,否则返回false。
boolean isFair()
// 查询当前线程是否保持此锁。
boolean isHeldByCurrentThread()
// 查询此锁是否由任意线程保持。
boolean isLocked()
// 获取锁。
void lock()
// 如果当前线程未被中断,则获取锁。
void lockInterruptibly()
// 返回用来与此 Lock 实例一起使用的 Condition 实例。
Condition newCondition()
// 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
boolean tryLock()
// 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
boolean tryLock(long timeout, TimeUnit unit)
// 试图释放此锁。
void unlock()

ReentrantLock示例:生产者消费者

测试1:用独占锁控制生产和消费,确保不会同时发生

package com.template.ProduceConsume;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; // LockTest1.java
// 仓库
class Depot {
private int size; // 仓库的实际数量
private Lock lock; // 独占锁 public Depot() {
this.size = 0;
this.lock = new ReentrantLock();
} public void produce(int val) {
lock.lock();
try {
size += val;
System.out.printf("%s produce(%d) --> size=%d\n",
Thread.currentThread().getName(), val, size);
} finally {
lock.unlock();
}
} public void consume(int val) {
lock.lock();
try {
size -= val;
System.out.printf("%s consume(%d) <-- size=%d\n",
Thread.currentThread().getName(), val, size);
} finally {
lock.unlock();
}
}
}; // 生产者
class Producer {
private Depot depot; public Producer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程向仓库中生产产品。
public void produce(final int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
} // 消费者
class Customer {
private Depot depot; public Customer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程从仓库中消费产品。
public void consume(final int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
} public class test {
public static void main(String[] args) {
Depot mDepot = new Depot();
Producer mPro = new Producer(mDepot);
Customer mCus = new Customer(mDepot); mPro.produce(60);
mPro.produce(120);
mCus.consume(90);
mCus.consume(150);
mPro.produce(110);
}
}

2.去掉锁之后

3.用condition保证仓库库存不为负数,仓库容量有限制

package com.template.ProduceConsume;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition; // LockTest3.java
// 仓库
class Depot {
private int capacity; // 仓库的容量
private int size; // 仓库的实际数量
private Lock lock; // 独占锁
private Condition fullCondtion; // 生产条件
private Condition emptyCondtion; // 消费条件 public Depot(int capacity) {
this.capacity = capacity;
this.size = 0;
this.lock = new ReentrantLock();
this.fullCondtion = lock.newCondition();
this.emptyCondtion = lock.newCondition();
} public void produce(int val) {
lock.lock();
try {
// left 表示“想要生产的数量”(有可能生产量太多,需多此生产)
int left = val;
while (left > 0) {
// 库存已满时,等待“消费者”消费产品。
while (size >= capacity)
fullCondtion.await();
System.out.println("生产开始了");
// 获取“实际生产的数量”(即库存中新增的数量)
// 如果“库存”+“想要生产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满仓库)
// 否则“实际增量”=“想要生产的数量”
int inc = (size+left)>capacity ? (capacity-size) : left;
size += inc;
left -= inc;
System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, inc, size);
// 通知“消费者”可以消费了。
emptyCondtion.signal();
}
} catch (InterruptedException e) {
} finally {
lock.unlock();
}
} public void consume(int val) {
lock.lock();
try {
// left 表示“客户要消费数量”(有可能消费量太大,库存不够,需多此消费)
int left = val;
while (left > 0) {
// 库存为0时,等待“生产者”生产产品。
while (size <= 0)
emptyCondtion.await();
System.out.println("消费开始");
// 获取“实际消费的数量”(即库存中实际减少的数量)
// 如果“库存”<“客户要消费的数量”,则“实际消费量”=“库存”;
// 否则,“实际消费量”=“客户要消费的数量”。
int dec = (size<left) ? size : left;
size -= dec;
left -= dec;
System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, dec, size);
fullCondtion.signal();
}
} catch (InterruptedException e) {
} finally {
lock.unlock();
}
} public String toString() {
return "capacity:"+capacity+", actual size:"+size;
}
}; // 生产者
class Producer {
private Depot depot; public Producer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程向仓库中生产产品。
public void produce(final int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
} // 消费者
class Customer {
private Depot depot; public Customer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程从仓库中消费产品。
public void consume(final int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
} public class test {
public static void main(String[] args) {
Depot mDepot = new Depot(100);
Producer mPro = new Producer(mDepot);
Customer mCus = new Customer(mDepot); mPro.produce(60);
mPro.produce(120);
mCus.consume(90);
mCus.consume(150);
mPro.produce(110);
}
}

引入了两个Condition条件,一个条件是是满了停止生产,等待通知进行生产,一个是空了停止消费,有了通知消费。

多线程编程-- part5.1 互斥锁ReentrantLock的更多相关文章

  1. 多线程编程-- part5.1 互斥锁之公平锁-获取锁

    基本概念 1.AQS:AbstractQueuedSynchronizer类 AQS是java中管理“锁”的抽象类,锁的许多公共方法都是在这个类中实现.AQS是独占锁(例如,ReentrantLock ...

  2. 多线程编程-- part5.1 互斥锁之非公平锁-获取与释放

    非公平锁之获取锁 非公平锁和公平锁在获取锁的方法上,流程是一样的:它们的区别主要表现在“尝试获取锁的机制不同”.简单点说,“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待):而 ...

  3. 多线程编程-- part5.1 互斥锁之公平锁-释放锁

    释放公平锁 1.unlock() unlock()在ReentrantLock.java中实现的,源码如下: public void unlock() { sync.release(1); } 说明: ...

  4. python多线程编程(3): 使用互斥锁同步线程

    问题的提出 上一节的例子中,每个线程互相独立,相互之间没有任何关系.现在假设这样一个例子:有一个全局的计数num,每个线程获取这个全局的计数,根据num进行一些处理,然后将num加1.很容易写出这样的 ...

  5. concurrent(三)互斥锁ReentrantLock & 源码分析

    参考文档:Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock:http://www.cnblogs.com/skywang12345/p/3496101.html Reentr ...

  6. Java并发编程实战 03互斥锁 解决原子性问题

    文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...

  7. Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

    本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...

  8. 【漫画】互斥锁ReentrantLock不好用?试试读写锁ReadWriteLock

    ReentrantLock完美实现了互斥,完美解决了并发问题.但是却意外发现它对于读多写少的场景效率实在不行.此时ReentrantReadWriteLock来救场了!一种适用于读多写少场景的锁,可以 ...

  9. C#多线程编程(7)--锁

    一提到线程同步,就会提到锁,作为线程同步的手段之一,锁总是饱受质疑.一方面锁的使用很简单,只要在代码不想被重入的地方(多个线程同时执行的地方)加上锁,就可以保证无论何时,该段代码最多有一个线程在执行: ...

随机推荐

  1. python sqlalchemy 进行 mysql 数据库操作

    1. 进行mysql数据库的创建,如果已经存在,就相当于进行数据库的连接操作 from sqlalchemy import create_engine from sqlalchemy.ext.decl ...

  2. Android jni/ndk编程一:jni初级认识与实战体验

    Android平台很多地方都可以看到jni的身影,比如之前接触到一个投屏的项目,主要的代码是c/c++写的,然后通过Jni供Java层调用;另外,就拿Android系统中的Service来说,很多的S ...

  3. Jmeter实现简单web负载测试

    Jmeter实现简单web负载测试 简介 Apache JMeter是Apache组织开发的基于Java的压力测试工具.用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域. ...

  4. Xib中设置控件的圆角、边框效果

    设置控件的圆角和边框效果有两种方式: 1.代码实现: self.myView.layer.masksToBounds = YES; self.myView.layer.cornerRadius = ; ...

  5. Opencv中的WMesh

    费了半天劲,终于把这个WMesh类搞懂了,可惜效果不佳,比Matlab中的mesh差多了. 使用WMesh前,需要有一个Mesh对象,Mesh是三维数据点的基本几何信息.颜色信息.索引信息等集成的对象 ...

  6. Python基础知识(程序结构)

    流程控制语句 选择语句.条件表达式.循环语句.跳转语句.pass空语句 程序结构三种基本结构 顺序结构.选择结构.循环结构 顺序结构 按照代码顺序依次运行 选择结构 根据条件表达式结果选择执行不同的语 ...

  7. CISCO路由器WAN口动态ISP配置

        Building configuration... version 15.0 service timestamps debug datetime msec service timestamps ...

  8. 【DSP开发】回马枪要你命 德州仪器发布最强ARM芯片Keystone II

    之前许多传闻称德州仪器将会彻底放弃OMAP系列ARM处理器,从此离开手持设备的江湖.如果你信以为真,那可就太小看德州仪器这个老狐狸了--要知道德州仪器诞生的比Intel都还早几年.三小时前,德州仪器宣 ...

  9. so的封装和使用

    背景 在linux平台下,要实现函数的封装,一般采用的是so动态库的形式 实现了函数的封装就意味着实现过程的隐藏 可以实现跨平台和跨语言的使用 实施步骤 生成so动态库 编写相应的c文件代码,实现函数 ...

  10. C学习笔记-文件操作

    文件操作大致分三步 打开文件 读写文件 关闭文件 二进制和文本模式的区别 在windows系统中,文本模式下,文件以"\r\n"代表换行.若以文本模式打开文件,并用fputs等函数 ...