关键词:
条件变量都实现了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函数 查看详情
rust语言特性之变量
...言。这几天我把RUST语法过了一遍。有了其它编程语言的基础,RUST语法学起来不难。但RUST毕竟是一门全新设计的语言,如果和现有语言完全一样,那就失去了存在的价值。RUST作为一门年轻的语言,博采众长,... 查看详情
使用线程间通信之条件变量
...3;写安卓下的一个通讯程序。作为jni库给java调用,採用多线程轮询遇到一个问题描写叙述例如以下:A线程收到数据,放入队列,是生产者。B、C、D若干个线轮询训消息队列,假设队列有数据就取出进行处理,没数据就Sleep(T)歇息... 查看详情
java特性之继承
...代码的复用,节约开发时间。在java中继承是指在父类的基础上扩展功能,继承中分为子类和父类。类有两种重要成员:成员变量和方法。java中子类通过关键字extends可以获得父类的成员变量和方法。子类的成员中可以有自己声明... 查看详情