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

条件变量都实现了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();             //唤醒所有存款操作
        }
}
时间: 2024-08-18 11:24:26

Java基础之线程新特性条件变量的相关文章

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

(接上文<线程基础:JDK1.5+(9)--线程新特性(中)>) 3-4.CountDownLatch:同步器 上文中我们主要讲解了JDK1.5+中提供的一个重要工具:Semaphore信号量,并且用这个工具第一次实现了"100米赛跑"的需求.在第一次的实现中,我们还运用了"线程专栏"中已介绍的多个知识点,包括锁.线程池.队列.Callable接口等. 但实际上第一次实现的"100米赛跑"的需求,离我们真正的需求还有一定的距离:在我们

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

(接上文<线程基础:JDK1.5+(8)--线程新特性(上)>) 3.工作在多线程环境下的"计数器": 从这个小节開始,我们将以一个"赛跑"的样例.解说JDK1.5环境下一些线程控制工具(包含Semaphore.CountDownLatch和java.util.concurrent.atomic子包),而且复习这个专题讲到的知识点:同步快.锁.线程池.BlockingQueue.Callable等. 3-1. 赛跑比赛的需求 如今您不仅能够通过我们已经介

JAVA JDK1.5-1.9新特性

JAVA JDK1.5-1.9新特性 1.5 1.自动装箱与拆箱: 2.枚举(常用来设计单例模式) 3.静态导入 4.可变参数 5.内省 1.6 1.Web服务元数据 2.脚本语言支持 3.JTable的排序和过滤 4.更简单,更强大的JAX-WS 5.轻量级Http Server 6.嵌入式数据库 Derby 1.7 1,switch中可以使用字串了 2.运用List tempList = new ArrayList<>(); 即泛型实例化类型自动推断 3.语法上支持集合,而不一定是数组 4

Java核心技术之Java8新特性-Lambda表达式

1 总体说明 Java8新特性概述 函数式接口 Lambda表达式(闭包) 2 Java8新特性概述 Oracle公司于2014年3月发布了Java8正式版,该版本是自JDK5.0以来最具革命性的版本. Java8为Java语言.编译器.类库和JVM带来了大量的新特性.接下来的内容将会详细说明Java8在Java语言方面的新特性以及它们的使用场景. 3 函数式接口 Java8引入的一个核心概念是函数式接口(Functional Interfaces):如果一个接口定义一个唯一的抽象方法,那么这个

Extjs5.0从入门到实战开发信息管理系统(Extjs基础、Extjs5新特性、Spring、Spring mvc、Mybatis)视频教程

Extjs5.0从入门到实战开发信息管理系统(Extjs基础.Extjs5新特性.Spring.Spring mvc.Mybatis)视频教程下载   联系QQ:1026270010 Extjs作为一款优秀的JS前端开发框架以其良好的架构.丰富的UI组件库.完善的文档和社区支持等诸多优点拥有广泛的市场应用空间,开发人员无需过多的关注HTML.CSS甚至各种常用JS算法,只需把精力放在业务逻辑上,利用各种组件的相互组合调用便可轻松而高效的开发出系统的前端页面. Extjs5在之前版本的基础上又推出

Java引入的一些新特性

Java引入的一些新特性 Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本. Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等. 随着代码库越来越大,其创建也越来越复杂,这也就造成了我们在编写代码的过程中很难真正地对代码进行封装,类路径本身也存在一些问题,越来越多的问题也随之而来,比如数据和内存的溢出等,但是越来越复杂的代码库也为我们程序的编写

(CZ深入浅出Java基础)线程笔记

一.线程的引入 1.多线程概述 1.1.进程 a.正在运行的程序,是系统进行资源分类和调用的独立单位. b.每个进程都有它自己的内存空间和系统资源. 1.2.线程 a.是进程中的单个顺序控制流,是一条执行路径. b.一个进程如果只有一条路径,则称为单线程程序. c.一个进程如果有多条执行路径,则称为多线程程序. 1.3.小结 线程多的进程抢到CPU执行权的概率大,但是仍具有随机性. 2.Java程序运行原理 2.1.Java运行 Java命令会启动Java虚拟机,启动JVM,等于启动了一个应用程

线程&mdash;同步之条件变量

条件变量:允许线程阻塞等待另一个线程发送信号唤醒.条件变量被用来阻塞一个线程,当条件不满足时,线程解开相应的互斥锁并等待条件发生变化.如果其他线程改变了条件变量,并且使用条件变量换型一个或多个正被此条件变量阻塞的线程.这些线程将重新锁定互斥锁并重新测试条件是否满足.条件变量被用来进行线程间的同步. thread 1 con = threading.Condition()    #创建条件变量 while True: do something con.acquire()    #获取锁 con.n

Linux程序设计学习笔记----多线程编程之线程同步之条件变量

转载请注明出处:http://blog.csdn.net/suool/article/details/38582521. 基本概念与原理 互斥锁能够解决资源的互斥访问,但是在某些情况下,互斥并不能解决问题,比如两个线程需 要互斥的处理各自的操作,但是一个线程的操作仅仅存在一种条件成立的情况下执行,一旦错过不可再重现,由于线程间相互争夺cpu资源,因此在条件成立的时候,该线程不一定争夺到cpu而错过,导致永远得不到执行..... 因此需要某个机制来解决此问题,更重要的是,线程仅仅只有一种情况需要执