我们知道用于解决多线程同步安全问题的方式有
synchronized:隐式锁
1.同步代码块
2.同步方法
synchronized:隐式锁
1.同步代码块
2.同步方法
jdk 1.5 后同步锁 Lock,是一个显示锁,需要通过 lock() 方法上锁,必须通过 unlock() 方法进行释放锁
下面我们介绍Lock同步以及Condition的线程通信
package com.buerc.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestProducerAndConsumer {
public static void main(String[] args) {
Clerk clerk=new Clerk();
Producer producer=new Producer(clerk);
Consumer consumer=new Consumer(clerk);
Producer producer1=new Producer(clerk);
Consumer consumer1=new Consumer(clerk);
new Thread(producer,"生产者A1").start();
new Thread(consumer,"消费者B1").start();
new Thread(producer1,"生产者A2").start();
new Thread(consumer1,"消费者B2").start();
}
}
class Clerk{
private static final int TOTAL=10;//库存总量
private int num=0;//当前数量
private Lock lock=new ReentrantLock();;
private Condition condition=lock.newCondition();
public void get() {
lock.lock();
try {
if(num>=TOTAL) {
System.out.println("库存已满,无法进货");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+"进货,当前数量:"+(++num));
condition.signalAll();
}
} finally {
lock.unlock();
}
}
public void sale() {
lock.lock();
try {
if(num<=0) {
System.out.println("库存已空,无法卖货");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+"卖货,当前数量:"+(--num));
condition.signalAll();
}
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable{
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk=clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.get();
}
}
}
class Consumer implements Runnable{
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk=clerk;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
clerk.sale();
}
}
}
如上例子,生产者消费者例子,通过Lock显示锁同步,以及通过Condition控制线程通信。ReentrantLock 实现了Lock 接口,并提供了与synchronized 相同的互斥性和内存可见性。但相较于synchronized 提供了更高的处理锁的灵活性。Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用Object.wait 访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个Lock 可能与多个Condition 对象关联。为了避免兼容性问题,Condition 方法的名称与对应的Object 版本中的不同。在Condition 对象中,与wait、notify 和notifyAll 方法对应的分别是await、signal 和signalAll。Condition 实例实质上被绑定到一个锁上。要为特定Lock 实例获得Condition 实例,请使用其newCondition() 方法。下面在介绍Condition控制线程通信以便更好了解。package com.buerc.thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AlternateExecution {
public static void main(String[] args) {
AlternateDemo alternateDemo=new AlternateDemo();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <=20; i++) {
alternateDemo.loopA(i);
}
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <=20; i++) {
alternateDemo.loopB(i);
}
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <=20; i++) {
alternateDemo.loopC(i);
}
}
},"C").start();
}
}
class AlternateDemo{
private Lock lock=new ReentrantLock();
private Condition condition1=lock.newCondition();
private Condition condition2=lock.newCondition();
private Condition condition3=lock.newCondition();
private int num=1;//用于标识
public void loopA(int index) {
lock.lock();
try {
if (num != 1) {
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"\t"+1+"\t"+index+"轮");
num++;
condition2.signal();//唤醒2
} finally {
lock.unlock();
}
}
public void loopB(int index) {
lock.lock();
try {
if (num != 2) {
try {
condition2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"\t"+1+"\t"+index+"轮");
num++;
condition3.signal();//唤醒3
} finally {
lock.unlock();
}
}
public void loopC(int index) {
lock.lock();
try {
if (num != 3) {
try {
condition3.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"\t"+1+"\t"+index+"轮");
System.out.println("---------------------");
num=1;
condition1.signal();//唤醒1
} finally {
lock.unlock();
}
}
}