ReentrantLock 可重用锁
1. 同一个线程未释放锁之前获取同一把锁
一个线程在获取了锁之后,再次去获取了同一个锁,这时候仅仅是把使用计数 +1
package lock9_method.holdCount;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by lenovo on 2018/5/10.
*/
public class Service {
public ReentrantLock lock = new ReentrantLock();
public void method() {
try {
lock.lock();
System.out.println(lock.getHoldCount());
Thread.sleep(1000);
method2();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void method2(){
lock.lock();
System.out.println(lock.getHoldCount());
lock.unlock();
}
}
package lock9_method.holdCount;
/**
* Created by lenovo on 2018/5/10.
*/
public class Main {
public static void main(String[] args) {
Service service = new Service();
Runnable runnable = new Runnable() {
@Override
public void run() {
for(int i=0;i<10;i++){
service.method();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
Thread countThread = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
//当前线程拥有 该锁的计数,在这调用肯定为 0
System.out.println("当前锁被线程a 持有计数:"+service.lock.getHoldCount());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
countThread.start();
}
}
输出:
1
2
1
2
1
2
1
2
1
当前锁被线程a 持有计数:0
2
1
2
1
当前锁被线程a 持有计数:0
2. 使用 ReentrantLock 、Condition演示简单等待唤醒机制
package lock2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by lenovo on 2018/5/3.
*/
public class MyService206 {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void waitMethod() {
try {
lock.lock();
for (int i = 0; i < 3; i++) {
System.out.println("wait:" + i);
}
condition.await();
for (int i = 4; i < 6; i++) {
System.out.println("wait:" + i);
}
lock.unlock();
System.out.println("wait方法中锁被释放");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void signalMethod() {
lock.lock();
for (int i = 0; i < 3; i++) {
System.out.println("notify:" + i);
}
condition.signal();
for (int i = 4; i < 6; i++) {
System.out.println("notify:" + i);
}
lock.unlock();
System.out.println("notify 方法中锁被释放");
}
}
package lock2;
/**
* Created by lenovo on 2018/5/3.
*/
public class ThreadA extends Thread {
private MyService206 myService206;
public ThreadA(MyService206 myService206) {
this.myService206 = myService206;
}
@Override
public void run() {
myService206.waitMethod();
}
}
package lock2;
/**
* Created by lenovo on 2018/5/3.
*/
public class ThreadB extends Thread {
private MyService206 myService206;
public ThreadB(MyService206 myService206) {
this.myService206 = myService206;
}
@Override
public void run() {
myService206.signalMethod();
}
}
package lock2;
/**
* 使用 Condition实现简单等待唤醒机制
* Created by lenovo on 2018/5/3.
*/
public class Run206 {
public static void main(String[] args) {
MyService206 myService206 = new MyService206();
ThreadA threadA = new ThreadA(myService206);
threadA.start();
ThreadB threadB = new ThreadB(myService206);
threadB.start();
}
}
输出:
wait:0
wait:1
wait:2
notify:0
notify:1
notify:2
notify:4
notify:5
wait:4
wait:5
wait方法中锁被释放
notify 方法中锁被释放
3. 同一把锁、多个 Condition 实现唤醒 指定等待线程
package lock4;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by lenovo on 2018/5/3.
*/
public class MyService {
ReentrantLock lock = new ReentrantLock();
private Condition conditionA = lock.newCondition();
private Condition conditionB = lock.newCondition();
public void awaitA() {
try {
lock.lock();
for (int i = 0; i < 2; i++) {
System.out.println("awaitA: " + i);
}
conditionA.await();
for (int i = 3; i < 5; i++) {
System.out.println("awaitA: " + i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("awaitA unlock");
}
}
public void awaitB() {
try {
lock.lock();
for (int i = 0; i < 2; i++) {
System.out.println("awaitB: " + i);
}
conditionB.await();
for (int i = 3; i < 5; i++) {
System.out.println("awaitB: " + i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("awaitB unlock");
}
}
public void signalAll_A() {
try {
lock.lock();
conditionA.signalAll();
System.out.println("线程 A 被唤醒");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalAll_B() {
try {
lock.lock();
conditionB.signalAll();
System.out.println("线程 B 被唤醒");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
package lock4;
/**
* Created by lenovo on 2018/5/3.
*/
public class ThreadA extends Thread {
private MyService myService;
public ThreadA(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.awaitA();
}
}
package lock4;
/**
* Created by lenovo on 2018/5/3.
*/
public class ThreadB extends Thread {
private MyService myService;
public ThreadB(MyService myService) {
this.myService = myService;
}
@Override
public void run() {
myService.awaitB();
}
}
package lock4;
/**
* Created by lenovo on 2018/5/3.
* 使用多个 Condition 实现通知指定 等待线程
*
*/
public class Run212 {
public static void main(String[] args) {
MyService myService = new MyService();
ThreadA threadA = new ThreadA(myService);
ThreadB threadB = new ThreadB(myService);
threadA.start();
threadB.start();
try {
Thread.sleep(4000);
myService.signalAll_A();
Thread.sleep(3000);
myService.signalAll_B();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出
awaitB: 0
awaitB: 1
awaitA: 0
awaitA: 1
线程 A 被唤醒
awaitA: 3
awaitA: 4
awaitA unlock
线程 B 被唤醒
awaitB: 3
awaitB: 4
awaitB unlock
4. 使用 ReentrantLock 和 Condition实现生产者消费者模式
4.1 缓存中只支持一个值
package lock5_producer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by lenovo on 2018/4/23.
*/
public class MyService213 {
private ReentrantLock reentrantLock = new ReentrantLock();
private Condition condition = reentrantLock.newCondition();
private boolean hasValue = false;
/**
* 生产者
*/
public void set() {
try {
reentrantLock.lock();
while (hasValue == true) {
// 有值,生产者线程等待
condition.await();
}
// 无值
System.out.println("生产者在生产...");
hasValue = true;
condition.signal(); // 生产之后 唤醒 消费者
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
/**
* 消费者
*/
public void get() {
try {
reentrantLock.lock();
while (hasValue == false) {
// 无值,消费者在等待
condition.await();
}
System.out.println("消费者在消费");
hasValue = false;
condition.signal(); // 消费完之后唤醒生产者
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
}
package lock5_producer;
/**
* Created by lenovo on 2018/4/23.
*/
public class MyThreadA extends Thread {
private MyService213 myService213;
public MyThreadA(MyService213 myService213) {
this.myService213 = myService213;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
myService213.get();
}
}
}
package lock5_producer;
/**
* Created by lenovo on 2018/4/23.
*/
public class MyThreadB extends Thread {
private MyService213 myService213;
public MyThreadB(MyService213 myService213){
this.myService213 = myService213;
}
@Override
public void run() {
for(int i=0;i<100;i++){
myService213.set();
}
}
}
package lock5_producer;
/**
* Created by lenovo on 2018/4/23.
* ReentrantLock 、Condition 实现生产者消费者模式(缓存中数据最大值为 1)
*/
public class Run213 {
public static void main(String[] args) {
MyService213 myService213 = new MyService213();
MyThreadA myThreadA = new MyThreadA(myService213);
myThreadA.start();
MyThreadB myThreadB = new MyThreadB(myService213);
myThreadB.start();
}
}
输出:
生产者在生产...
消费者在消费
生产者在生产...
消费者在消费
生产者在生产...
消费者在消费
生产者在生产...
消费者在消费
4.2 缓存支持多个值
package lock6_consumer;
import com.sun.org.apache.xml.internal.resolver.readers.ExtendedXMLCatalogReader;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by lenovo on 2018/4/23.
*/
public class MyService215 {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private int valueCount = 0;
private int bufferMaxSize = 20;
/**
* 生产者
*/
public void set() {
try {
lock.lock();
while (valueCount == bufferMaxSize) {
// 如果缓存已满,释放锁等待
condition.await();
}
// 唤醒等待线程
condition.signalAll();
// 缓存未满
valueCount++; // 生产一个 添加到缓存中
System.out.println("生产者生产,缓存中的数据共" + valueCount + "个");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 消费者
*/
public void get() {
try {
lock.lock();
while (valueCount == 0) {
condition.await();
}
condition.signalAll();
// 消费
valueCount--;
System.out.println("消费者消费,缓存中的数据剩余:" + valueCount + " 个");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
/**
* Created by lenovo on 2018/4/23.
*/
public class MyThreadA extends Thread {
private MyService215 myService213;
public MyThreadA(MyService215 myService213) {
this.myService213 = myService213;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
myService213.get();
}
}
}
public class MyThreadB extends Thread {
private MyService215 myService213;
public MyThreadB(MyService215 myService213){
this.myService213 = myService213;
}
@Override
public void run() {
for(int i=0;i<100;i++){
myService213.set();
}
}
}
public class Run215 {
public static void main(String[] args) {
MyService215 myService213 = new MyService215();
MyThreadB consumer = new MyThreadB(myService213);
consumer.start();
MyThreadA producer = new MyThreadA(myService213);
producer.start();
}
}
输出:
生产者生产,缓存中的数据共1个
生产者生产,缓存中的数据共2个
生产者生产,缓存中的数据共3个
生产者生产,缓存中的数据共4个
消费者消费,缓存中的数据剩余:3 个
消费者消费,缓存中的数据剩余:2 个
消费者消费,缓存中的数据剩余:1 个
消费者消费,缓存中的数据剩余:0 个
生产者生产,缓存中的数据共1个
生产者生产,缓存中的数据共2个
生产者生产,缓存中的数据共3个
生产者生产,缓存中的数据共4个
生产者生产,缓存中的数据共5个
....
4.3 使用不同的 Condition 唤醒同类线程
在 4.2 中使用 condition.signalAll() 是为了唤醒所有处于WAITING的线程,避免出现假死现象,但如果唤醒的是同类线程, 则又会进入WAITING状态,浪费资源
解决方案: 一类线程使用一个 Condition对象
package lock5_producer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by lenovo on 2018/5/11.
*/
public class Service {
private ReentrantLock lock = new ReentrantLock();
private Condition producerCondition = lock.newCondition();
private Condition consumerCondition = lock.newCondition();
private int bufferMaxSize = 2;
private int nowCount = 0;
public void produce() {
try {
lock.lock();
while (nowCount == bufferMaxSize) {
System.out.println("生产者: "+Thread.currentThread().getName()+" 等待");
producerCondition.await();
System.out.println("生产者: "+Thread.currentThread().getName()+" 被唤醒");
}
nowCount++;
consumerCondition.signal();
System.out.println("生产者: "+Thread.currentThread().getName()+"生产产品,总计" + nowCount);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void consumer() {
try {
lock.lock();
while (nowCount == 0) {
System.out.println("消费者: "+Thread.currentThread().getName()+"等待");
consumerCondition.await();
System.out.println("消费者: "+Thread.currentThread().getName()+"被唤醒");
}
nowCount--;
System.out.println("消费者: "+Thread.currentThread().getName()+" 消费产品,剩余 " + nowCount);
producerCondition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
package lock5_producer;
/**
* Created by lenovo on 2018/5/11.
*/
public class Main {
public static void main(String[] args) {
Service service = new Service();
Runnable proRun = new Runnable() {
@Override
public void run() {
service.produce();
}
};
Runnable conRun = new Runnable() {
@Override
public void run() {
service.consumer();
}
};
Thread[] consumer = new Thread[30];
Thread[] producer = new Thread[30];
for (int i = 0; i < 30; i++) {
consumer[i] = new Thread(conRun);
consumer[i].setName("consumer" + i);
producer[i] = new Thread(proRun);
producer[i].setName("producer" + i);
}
for (int i = 0; i < 30; i++) {
consumer[i].start();
producer[i].start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出
生产者: producer25 等待
生产者: producer2 等待
消费者: consumer23被唤醒
消费者: consumer23 消费产品,剩余 1
消费者: consumer29 消费产品,剩余 0
消费者: consumer28等待
生产者: producer27生产产品,总计1
消费者: consumer27 消费产品,剩余 0
消费者: consumer25等待
生产者: producer24生产产品,总计1
消费者: consumer24 消费产品,剩余 0
生产者: producer25 被唤醒
生产者: producer25生产产品,总计1
生产者: producer2 被唤醒
生产者: producer2生产产品,总计2
网友评论