用ReentrantLock和Condition实现线程间通信

在Java多线程中,除了使用synchronize关键字来实现线程之间的同步互斥,还可以使用JDK1.5中新增的RetrantLock类来实现同样的效果。RetrantLock类的扩展功能也更加强大,比如具有嗅探锁定,多路分支通知等功能,在使用上也比synchronize更为灵活。

借助于Condition对象,RetrantLock可以实现类似于Object的wait和notify/notifyAll功能。使用它具有更好的灵活性,在一个Lock对象里面可以创建多个Condition(对象监视器)实例,线程对象可以注册在指定的Condition对象中,从而可以有选择性的进行线程通知,实现多路通知功能,在调度线程上更加灵活。

每一个 Lock 可以有任意数据的 Condition 对象, Condition 是与 Lock 绑定的,所以就有 Lock 的公平性特性:如果是公平锁,线程为按照FIFO的顺序从 Condition.await 中释放,如果是非公平锁,那么后续的锁竞争就不保证FIFO顺序了。

下面是一个生产者、消费者的示例:

/*
 * 买家线程,当书店中有书的时候买书
 */
public class Buyer extends Thread {
    private BookStore bookStore;

    public Buyer(BookStore bookStore) {
        this.bookStore = bookStore;
    }

    @Override
    public void run() {
        while (true) {
            bookStore.removeBook();
        }
    }
}
/*
 * 售货员线程,当书店中还有空位,买进书籍
 */
public class Seller extends Thread {
    private BookStore bookStore;
    public Seller(BookStore bookStore) {
        this.bookStore = bookStore;
    }

    @Override
    public void run() {
        while (true) {
            bookStore.addBook();
        }
    }
}
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 书店类
 */
public class BookStore {
    private ArrayList books = new ArrayList();
    private ReentrantLock lock = new ReentrantLock(false);
    private Condition buyCondition = lock.newCondition();
    private Condition sellCondition = lock.newCondition();
    public void addBook() {
        lock.lock();
        while (books.size() >= 1) {
            try {
                System.out.println(Thread.currentThread().getName() + "等待图书售出");
                sellCondition.await();  //售货员等待书店出现空位
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        books.add(1);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "购入了一本书,剩余:" + books.size());
        buyCondition.signal();  //通知买家买书
        lock.unlock();
    }

    public void removeBook() {
        lock.lock();
        while (books.size() <= 0) {
            try {
                System.out.println(Thread.currentThread().getName() + "等待购入图书");
                buyCondition.await();  //买家等待书店进书
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        books.remove(0);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "买了一本书,剩余:" + books.size());
        sellCondition.signal();  //通知售货员进书
        lock.unlock();
    }
}
/*
 * 测试类
 */
public class Test {
    public static void main(String[] args) {
        BookStore bookStore = new BookStore();
        Buyer[]  buyers = new Buyer[5];
        Seller  sellers;
        //创建5个买家线程,负责买书
        for(int i = 0; i < 5; i++) {
            buyers[i] = new Buyer(bookStore);
        }
        //创建售货员线程,负责进书
        sellers = new Seller(bookStore);
        //启动线程
        sellers.start();
        for(int i = 0; i < 5; i++) {
            buyers[i].start();
        }
    }
}

运行结果:

从结果我们可以看到售货员线程和买家线程是交替运行的,这就是因为两类线程分别绑定了两个不同的Condition:buyCondition,sellCondition。从而实现了两类线程的交替唤醒。

时间: 2024-11-05 14:09:40

用ReentrantLock和Condition实现线程间通信的相关文章

经典笔试题:线程通信(使用重入锁(ReentrantLock)和条件队列(Condition)实现线程间通信)

经典笔试题: 1.自定义容器,提供新增元素(add)和获取元素数量(size)方法.2.启动两个线程.线程1向容器中新增10个数据.线程2监听容器元素数量,当容器元素数量为5时,线程2输出信息并终止. package com.gaopeng.programming.test2; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.conc

java多线程系列5-死锁与线程间通信

这篇文章介绍java死锁机制和线程间通信 死锁 死锁:两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象. 同步代码块的嵌套案例 public class MyLock { // 创建两把锁对象 public static final Object objA = new Object(); public static final Object objB = new Object(); } public class DieLock extends Thread { private b

多线程-线程间通信-多生产者多消费者示例

1.多线程-线程间通信-多生产者多消费者问题 多生产者和多消费者.等待唤醒机制. 产生了两个问题: 1.出现了多次连续生产,未消费,或者一个商品被消费多次. 解决:必须要--------每一个被唤醒的线程判断一次标记,所以将if判断改为while判断. 2.出现了死锁. 本方唤醒了本方,导致了所有的线程都等待了. 解决方式就是:唤醒所有等待的线程.这样既唤醒了本方也唤醒对方. 虽然解决了多生产消费的问题,但是有些低效. 解决方法一: 唤醒所有等待的线程 class Resource{     p

Java并发——线程间通信与同步技术

传统的线程间通信与同步技术为Object上的wait().notify().notifyAll()等方法,Java在显示锁上增加了Condition对象,该对象也可以实现线程间通信与同步.本文会介绍有界缓存的概念与实现,在一步步实现有界缓存的过程中引入线程间通信与同步技术的必要性.首先先介绍一个有界缓存的抽象基类,所有具体实现都将继承自这个抽象基类: public abstract class BaseBoundedBuffer<V> { private final V[] buf; priv

Java——线程间通信问题

 wait和sleep区别: 1.wait可以指定时间可以不指定.     sleep必须指定时间. 2.在同步时,对cpu的执行权和锁的处理不同.     wait:释放执行权,释放锁.     sleep:释放执行权,不释放锁. /* * 等待/唤醒机制 * 设计的方法: * 1.wait():让线程处于等待状态,被wait的线程会被存储到线程池中. * 2.notify():唤醒线程池中的一个线程(任意) * 3.notifyAll():唤醒线程池中的所有线程. * 这些方法都必须定义

Java多线程 二 线程间通信

线程间通信: 多个线程在处理同一资源,但是 等待唤醒机制 涉及的方法: 1.wait() 让线程处于冻结状态,被wait的线程会被存储到线程池中. 2.notify() 唤醒线程池中的一个线程(任意) 3.notifyAll() 唤醒线程池中的所有线程.. 这些方法都必须定义在同步中, 因为这些方法是用于操作线程状态的方法. 必须明确到底操作的那个锁上的线程. 为什么操作线程的方法wait notify notifyAll定义在了Object中. 因为这些方法是监视器方法,监视器其实就是锁. 锁

说说Java线程间通信

序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在一个同步块里设置boolean型成员变量hasDataToProcess为true,线程B也在同步块里读取hasDataToProcess这个成员变量:线程A和B必须获得指向一个MySignal共享实例的引用,以便进行通信:如果它们持有的引用指向不同的MySingal实例,那么彼此将不能检测到对方的

线程间通信和线程互斥

线程间通信 1> 线程间通信分为两种 主线程进入子线程(前面的方法都可以) 子线程回到主线程 2> 返回主线程 3> 代码 这个案例的思路是:当我触摸屏幕时,会在子线程加载图片,然后在主线程刷新UI界面 视图布局我就不写了,大家自己来吧,线程间通信代码如下: #pragma mark - 添加响应方法触发创建子线程并加载数据 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

线程同步--线程间通信

一.线程同步 线程的同步方法跟其他系统下类似,我们可以用原子操作,可以用 mutex,lock 等. iOS 的原子操作函数是以 OSAtomic 开头的,比如:OSAtomicAdd32, OSAtomicOr32 等等.这些函数可以直接使用,因为它 们是原子操作. iOS 中的 mutex 对应的是 NSLock,它遵循 NSLooking 协议,我们可以使用 lock, tryLock, lockBeforeData:来加锁,用 unLock 来解锁.使用示例: BOOL moreToDo