• 用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。从而实现了两类线程的交替唤醒。

  • 相关阅读:
    Transfer-Encoding: chunked
    使用Kubeadm搭建Kubernetes集群
    连载二:Oracle迁移文章大全
    今晚直播:WLS/WAS故障基本分析介绍
    判断用户是否登录
    row_number() over (partition by a.sql_id order by a.id desc ) r
    Django admin添加用户
    从数据仓库到百万标签库,精细化数据管理,这么做就够了
    用 C 语言开发一门编程语言 — 更好的语言
    ubuntu下 全然卸载火狐浏览器
  • 原文地址:https://www.cnblogs.com/cisol/p/6673190.html
Copyright © 2020-2023  润新知