多线程(线程间通信-生产消费者JDK5.0升级版)
JDC1.5中提供了多线程升级解决方案。(显示的锁机制以及显示的锁对象的等待唤醒的操作机制)
一个锁可以对应多个condition。
将同步synchronized替换成Lock操作。
将Objeck中的wait,notify, notifyAll,替换成Condution对象。
该对象可以Lock锁进行获取。
java.util.concurrent.locks: //需要导的Lock包
接口 Lock :
Lock实现提供比使用synchronized方法语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的Condition对象。
所有已知实现类:
ReentrantLock(常用), ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLocke
方法摘要:
void lock(): 获取锁。
void lockInterruptibly():如果当前线程未被中断,则获取锁。
Condition newCondition():返回绑定到此Lock实例的新Condition实例。
boolean tryLock():仅在调用时锁为空状态才获取该锁。
boolean tryLock(long time,TimeUnit unit):如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
void unlock():释放锁。
接口 Condition:
Condition将Object监视器方法(wait、notify和notifyAll)分解成截然不同的对象,以便通过将这些对象任意Lock实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock替代了synchronized方法和语句的使用,Condition替代Object监视器方法的使用。
方法摘要:
void await():造成当前线程在接到信号或被中断之前一直处于等待状态。
boolean await(long tim,TimeUnit unit):造成当前线程在接到信号、被中断或者到达指定等待时间之前一直处于等待状态。
long awaitNanos(long nanosTimeout):造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。
void awaitUninterruptibly():造成当前线程在接到信号之前一直处于等待状态。
boolean awaitUntil(Date deadline):造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。
void signal():唤醒一个等待线程。
void signalAll():唤醒全部等待线程。
public class ProducerConsumerDemo02 {
public static void main(String[] args) {
//创建一个资源的对象
Resource1 r = new Resource1();
//处理资源
Producer1 pro = new Producer1(r);
Consumer1 con = new Consumer1(r);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(pro);
Thread t4 = new Thread(con);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//资源管理
class Resource1 {
private String name; //产品名称
private int count = 1; //编号
private boolean flag = false; //资源空间标记点
//创建一个锁
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition(); //生产者的锁
private Condition condition_con = lock.newCondition(); //消费者的锁
//设置数据
//生产者有 t1 t3
public void set(String name) throws InterruptedException { //中断异常
lock.lock(); //获取锁
//将if换成while循环,并且唤醒线程唤醒全部就不会出现数据错误。
try {
while (flag)
//如果flag为真的话,生产者下来要等待
condition_pro.await(); //线程等待(如果我们抛异常的话,一抛程序就结束了,不会读到我们后面的程序,更不会读到unlock(),所以这里的异常只能处理不能抛)
this.name = name + "---" + count++; //这样写的话,我们存入一个产品,产品编号会自动加一
System.out.println(Thread.currentThread().getName() + "..生产者.." + this.name); //Thread.currentThread().getName():获取当前线程的名称
flag = true;
condition_con.signal(); //唤醒消费者的线程
} finally {
lock.unlock(); //释放锁(这句话一定要执行,就用finally)
}
}
//打印
//消费者有:t2 t4
public void out() throws InterruptedException {
lock.lock();
try {
while (!flag)
//消费者下来如果为真的话,就让消费者线程等待(用消费者锁)
condition_con.await();
System.out.println(Thread.currentThread().getName() + "..消费者......." + this.name);
flag = false;
//唤醒就唤醒生产者的锁。这里就不用signalAll()唤醒全部的线程了
condition_pro.signal();
} finally {
lock.unlock();
}
}
}
//生产者
class Producer1 implements Runnable {
private Resource1 res; //资源
public Producer1(Resource1 res) {
this.res = res;
}
@Override
public void run() {
while (true) {
try {
res.set("+商品+");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者
class Consumer1 implements Runnable {
private Resource1 res; //资源
public Consumer1(Resource1 res) {
this.res = res;
}
@Override
public void run() {
while (true) {
try {
res.out();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}