多线程(线程间通信-生产消费者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():唤醒全部等待线程。

 

怎么只唤醒对象的等待线程呢?

解决方法就是我创建锁的时候就分别创建生产者锁和消费者锁。两个锁互相唤醒就OK了。

生产者代码中生产完就唤醒消费者线程,消费者代码中消费完后就唤醒生产者线程(这样的话就可以唤醒对方的线程了)

在该例中,实现了本方只唤醒对方的操作。

例如程序:

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();
}
}
}
}
posted @ 2021-12-06 00:04  滔滔是个java小白  阅读(45)  评论(0编辑  收藏  举报