java基础之线程新特性条件变量

潇湘剑雨 潇湘剑雨     2022-08-02     720

关键词:

     条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细

package unit_fifteen;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/** 
* Java线程:条件变量 
* 
*/ 
public class Test {
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Thread t1 = new SaveThread("张三", myCount, 2000); 
                Thread t2 = new SaveThread("李四", myCount, 3600); 
                Thread t3 = new DrawThread("王五", myCount, 2700); 
                Thread t4 = new SaveThread("老张", myCount, 600); 
                Thread t5 = new DrawThread("老牛", myCount, 1300); 
                Thread t6 = new DrawThread("胖子", myCount, 800); 
                //执行各个线程
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                //关闭线程池
                pool.shutdown(); 
        } 
} 

/** 
* 存款线程类 
*/ 
class SaveThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        SaveThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        } 

        public void run() {
                myCount.saving(x, name); 
        } 
} 

/** 
* 取款线程类 
*/ 
class DrawThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        DrawThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        } 

        public void run() {
                myCount.drawing(x, name); 
        } 
} 


/** 
* 普通银行账户,不可透支 
*/ 
class MyCount { 
        private String oid;                        //账号
        private int cash;                            //账户余额
        private Lock lock =new ReentrantLock();                //账户锁
        private Condition _save = lock.newCondition();    //存款条件
        private Condition _draw = lock.newCondition();    //取款条件

        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        } 

        /** 
         * 存款 
         * 
         * @param x        操作金额
         * @param name 操作人
         */ 
        public void saving(int x, String name) {
                lock.lock();                        //获取锁
                if (x > 0) {
                        cash += x;                    //存款
                        System.out.println(name + "存款" + x +",当前余额为" + cash);
                } 
                _draw.signalAll();            //唤醒所有等待线程。
                lock.unlock();                    //释放锁
        } 

        /** 
         * 取款 
         * 
         * @param x        操作金额
         * @param name 操作人
         */ 
        public void drawing(int x, String name) {
                lock.lock();                                 //获取锁
                try {
                        if (cash - x < 0) {
                                _draw.await();             //阻塞取款操作
                        } else {
                                cash -= x;                     //取款
                                System.out.println(name + "取款" + x +",当前余额为" + cash);
                        } 
                        _save.signalAll();             //唤醒所有存款操作
                } catch (InterruptedException e) {
                        e.printStackTrace(); 
                } finally {
                        lock.unlock();                     //释放锁
                } 
        } 
}

 

假如我们不用锁和条件变量,如何实现此功能呢?下面是实现代码:

package unit_fifteen;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** 
* Java线程:不用条件变量
* 
*/ 
public class Test {
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Thread t1 = new SaveThread("张三", myCount, 2000); 
                Thread t2 = new SaveThread("李四", myCount, 3600); 
                Thread t3 = new DrawThread("王五", myCount, 2700); 
                Thread t4 = new SaveThread("老张", myCount, 600); 
                Thread t5 = new DrawThread("老牛", myCount, 1300); 
                Thread t6 = new DrawThread("胖子", myCount, 800); 
                //执行各个线程
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                //关闭线程池
                pool.shutdown(); 
        } 
} 

/** 
* 存款线程类 
*/ 
class SaveThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        SaveThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        } 

        public void run() {
                myCount.saving(x, name); 
        } 
} 

/** 
* 取款线程类 
*/ 
class DrawThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        DrawThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        } 

        public void run() {
                myCount.drawing(x, name); 
        } 
} 


/** 
* 普通银行账户,不可透支 
*/ 
class MyCount { 
        private String oid;                        //账号
        private int cash;                            //账户余额

        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        } 

        /** 
         * 存款 
         * 
         * @param x        操作金额
         * @param name 操作人
         */ 
        public synchronized void saving(int x, String name) {
                if (x > 0) {
                        cash += x;                    //存款
                        System.out.println(name + "存款" + x +",当前余额为" + cash);
                } 
                notifyAll();            //唤醒所有等待线程。
        } 

        /** 
         * 取款 
         * 
         * @param x        操作金额
         * @param name 操作人
         */ 
        public synchronized void drawing(int x, String name) {
                if (cash - x < 0) {
                        try {
                                wait(); 
                        } catch (InterruptedException e1) {
                                e1.printStackTrace(); 
                        } 
                } else {
                        cash -= x;                     //取款
                        System.out.println(name + "取款" + x +",当前余额为" + cash);
                } 
                notifyAll();             //唤醒所有存款操作
        } 
}

结合先前同步代码知识,举一反三,将此例改为同步代码块来实现,代码如下:

package unit_fifteen;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** 
* Java线程:改为同步代码块
* 
*/ 
public class Test {
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个线程池
                ExecutorService pool = Executors.newFixedThreadPool(2); 
                Thread t1 = new SaveThread("张三", myCount, 2000); 
                Thread t2 = new SaveThread("李四", myCount, 3600); 
                Thread t3 = new DrawThread("王五", myCount, 2700); 
                Thread t4 = new SaveThread("老张", myCount, 600); 
                Thread t5 = new DrawThread("老牛", myCount, 1300); 
                Thread t6 = new DrawThread("胖子", myCount, 800); 
                //执行各个线程
                pool.execute(t1); 
                pool.execute(t2); 
                pool.execute(t3); 
                pool.execute(t4); 
                pool.execute(t5); 
                pool.execute(t6); 
                //关闭线程池
                pool.shutdown(); 
        } 
} 

/** 
* 存款线程类 
*/ 
class SaveThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        SaveThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        } 

        public void run() {
                myCount.saving(x, name); 
        } 
} 

/** 
* 取款线程类 
*/ 
class DrawThread extends Thread {
        private String name;                //操作人
        private MyCount myCount;        //账户
        private int x;                            //存款金额

        DrawThread(String name, MyCount myCount, int x) {
                this.name = name;
                this.myCount = myCount;
                this.x = x;
        } 

        public void run() {
                myCount.drawing(x, name); 
        } 
} 
/** 
* 普通银行账户,不可透支 
*/ 
class MyCount { 
        private String oid;                        //账号
        private int cash;                            //账户余额

        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        } 

        /** 
         * 存款 
         * 
         * @param x        操作金额
         * @param name 操作人
         */ 
        public void saving(int x, String name) {
                if (x > 0) {
                        synchronized (this) {
                                cash += x;                    //存款
                                System.out.println(name + "存款" + x +",当前余额为" + cash);
                                notifyAll();            //唤醒所有等待线程。
                        } 
                } 
        } 

        /** 
         * 取款 
         * 
         * @param x        操作金额
         * @param name 操作人
         */ 
        public synchronized void drawing(int x, String name) {
                synchronized (this) {
                        if (cash - x < 0) {
                                try {
                                        wait(); 
                                } catch (InterruptedException e1) {
                                        e1.printStackTrace(); 
                                } 
                        } else {
                                cash -= x;                     //取款
                                System.out.println(name + "取款" + x +",当前余额为" + cash);
                        } 
                } 
                notifyAll();             //唤醒所有存款操作
        } 
}

 

线程基础:jdk1.5+——线程新特性(中)

(接上文《线程基础:JDK1.5+(8)——线程新特性(上)》)3、工作在多线程环境下的“计数器”:从这个小节開始,我们将以一个“赛跑”的样例。解说JDK1.5环境下一些线程控制工具(包含Semaphore、CountDownLatch和java.util.concurren... 查看详情

java8新特性之:optional

一.用Optional取代null   1.Optional类     java.util.Optional<T>是一个封装Optional值的类。     变量存在时,Optional类只是对类进行简单的封装。变量不存在时,缺失的值会被建模成一个“... 查看详情

java并发程序设计(16)并发锁之条件变量

...控任意指定的条件,在条件不满足时等待条件满足,其它线程在条件满足时可以通知等待条件的线程,从而唤醒等待中的线程。下面的代码实现了两件工作分别由两个线程轮流不断执行的效果。packagecom.test.concurrence;importja 查看详情

java基础之stream流(jdk1.8新特性)

定义JDK1.8中增加了Stream流,Stream流是一个来自数据源的元素队列并支持聚合操作。元素是特定类型的对象,形成一个队列,Java中的Stream并不会存储元素,而是按需计算数据源是流的来源,可以使集合,数组,I/Ochannel,生成器gene... 查看详情

java基础之optional类(jdk1.8新特性)

定义Optional是一个容器,它可以保存类型T的值,或者仅仅保存null,Optional类主要是用来避免空指针异常(NPE),其提供的一系列的方法配合Lambda表达式可以让代码更加清晰,语义化,以及避免了空指针异常的问题,这里要注意是... 查看详情

前端基础学习css新特性之变形

变形2D变形旋转变形将transform属性的值设置为rotate(),即可实现旋转变形;transform:rotate(45deg);若角度为正,这顺时针方向旋转,否则逆时针方向旋转;transform-origin属性可以使用transform-origin属性设置自己的自定... 查看详情

java基础之线程原子量

   所谓的原子量即操作变量的操作是“原子的”,该操作不可再分,因此是线程安全的。为何要使用原子变量呢,原因是多个线程对单个变量操作也会引起一些问题。在Java5之前,可以通过volatile、synchronized关键... 查看详情

java之1.8新特性

1.Lambda表达式   使用前提     1.必须是函数式接口     2.必须参数和局部变量等等都要一一对应   标准格式     (参数类型参数名)->{方法体}():方法的参数没有则不写如果多个,隔开       ->:代表... 查看详情

jdk5新特性之线程同步集合

一.传统集合:传统方式下的Collection在迭代集合时,不同意对集合进行改动:publicclassCollectionModifyExceptionTest{ publicstaticvoidmain(String[]args){ Collection<String>list=newArrayList<String>(); list.add("aaa&q 查看详情

java基础_jdk5常用特性

jdk5新特性1.JDK新特性——增强for(1).格式:for(元素数据类型变量:数组或者是Collection集合){使用变量即可,该变量就是元素}(2).好处简化了数组和集合的遍历。 (3).弊端增强for的目标不能为null (4).代码实现:publicclassTest{ publicstaticvoidmai... 查看详情

java最强最新知识体系总结(2021版)

一、Java基础知识1、基础知识分类内容链接Java基础【Java知识点详解1】缓存链接1Java基础【Java知识点详解2】动态代理链接2Java基础【Java知识点详解3】序列化与反序列化链接3Java基础【Java知识点详解4】泛型链接4Java基础【Java知识... 查看详情

java基础之线程阻塞队列

   阻塞队列是Java线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队... 查看详情

java8新特性之lambda表达式

简介Java8带来的新特性之一Lambda表达式,又称之为函数式编程,核心思想是将面向对象中的传递对象变为传递行为语法expression=(variable)->anctioneg:intsum=(x,y)->x+y;variable:相当于一个变量,可以有多个action:代码逻辑部分,可以是一... 查看详情

线程基础:jdk1.5+(10)——线程新特性(下)

(接上文《线程基础:JDK1.5+(9)——线程新特性(中)》)3-4、CountDownLatch:同步器上文中我们主要讲解了JDK1.5+中提供的一个重要工具:Semaphore信号量,并且用这个工具第一次实现了“100米赛跑”的需求。在第一次的实现中,... 查看详情

线程同步之经典模型——生产者消费者模型(代码片段)

...一个线程使“条件成立”使用时总是和互斥锁结合在一起基础APIpthread_cond_init函数,用于初始化条件变量pthread_cond_destory函数&#x 查看详情

rust语言特性之变量

...言。这几天我把RUST语法过了一遍。有了其它编程语言的基础,RUST语法学起来不难。但RUST毕竟是一门全新设计的语言,如果和现有语言完全一样,那就失去了存在的价值。RUST作为一门年轻的语言,博采众长,... 查看详情

使用线程间通信之条件变量

...3;写安卓下的一个通讯程序。作为jni库给java调用,採用多线程轮询遇到一个问题描写叙述例如以下:A线程收到数据,放入队列,是生产者。B、C、D若干个线轮询训消息队列,假设队列有数据就取出进行处理,没数据就Sleep(T)歇息... 查看详情

java特性之继承

...代码的复用,节约开发时间。在java中继承是指在父类的基础上扩展功能,继承中分为子类和父类。类有两种重要成员:成员变量和方法。java中子类通过关键字extends可以获得父类的成员变量和方法。子类的成员中可以有自己声明... 查看详情