这个概念是我在java编程思想一书中看到的 ,没怎么看懂,网上资料也不多,大多数都是摘自书中的概念,不过在谷歌上找到一篇还比较好理解并且有实例的文章,特此搬过来给不能翻墙的小伙伴

和传统的面向过程的并发模型不同,“活动对象”实际上是把对象封装成一个独立的线程。它有自己的执行线程,以及等待执行的任务列表。自由线程会按照一定的顺序执行任务列表的中的任务。而所有对对象方法的调用都会被转化成在线程上排队的一个队列。所以看上去,这个对象就会自动处理对这个对象方法的调用,而且暂时来不及处理的请求也会被缓存起来,但同时调用方法不会被阻塞,而是直接就返回了,所以又有了异步执行的特性。

什么是活动对象?

“活动对象”是并发编程模型的一种。“活动对象”实际上就是把对象封装成一个独立的线程。它有自己的执行线程,以及等待执行的任务列表。自由线程会按照一定的顺序执行任务列表的中的任务。而所有对对象方法的调用都会被转化成在线程上排队的一个队列。所以看上去,这个对象就会自动处理对这个对象方法的调用,而且暂时来不及处理的请求也会被缓存起来,但同时调用方法不会被阻塞,而是直接就返回了。所以又有了异步执行的特性。

核心是Future对象

活动对象模型的核心就是Future对象。原理就是通过Executor的submit()方法,把一个Callable请求提交给私有线程,立即返回一个Future对象,并插入一个结果队列。最后可以通过Future对象的isDone()方法判断结果是否计算完成。

另一个关键点就是对象的私有线程应该用Executors.newSingleThreadExecutor()这个单线程执行器。它维护着自己的无界阻塞队列,这里就免费成为了我们的消息队列。

代码示例

考虑下面这个场景:

汽车要打蜡(waxOn)和抛光(waxOff)。操作的步骤是:先打蜡,然后抛光,然后再上蜡,再抛光,循环往复。

传统的面向过程的并发模型

这是一个很简单的场景。按照传统的并发编程范式的思路,可以抽象成两个机器人:一个专门打蜡机器人,一个专门抛光的机器人。两个机器人各自代表一个线程,共同来操作汽车对象。用最简单的wait(),notifyAll()互相进行协作,两个机器人的线程如下:

  • 打蜡机器人:先打蜡,打完蜡叫醒抛光机器人,挂起,等待抛光机器人抛光完成。

  • 抛光机器人:先等打蜡机器人打蜡,被叫醒后开始抛光,完成后叫醒打蜡机器人,自己挂起等待打蜡机器人打蜡。

具体代码如下,汽车类Car有一个boolean域代表汽车上蜡的状态,true代表表面有蜡,false代表表面没蜡是抛光的。然后汽车封装了4个基本动作。把动作封装到Car类里,是为了方便套上互斥锁。

  • waxed(): 上蜡

  • buffed(): 抛光

  • waitForWaxing(): 等待上蜡

  • waitForBuffing(): 等待抛光

    class Car {private boolean waxOn = false;public synchronized void waxed() {waxOn = true; // Ready to buffnotifyAll();}public synchronized void buffed() {waxOn = false; // Ready for another coat of waxnotifyAll();}public synchronized void waitForWaxing() throws InterruptedException {while(waxOn == false){wait();}}public synchronized void waitForBuffing() throws InterruptedException {while(waxOn == true){wait();}}
    }
    

    打蜡机器人就是先打蜡,然后叫醒在Car互斥锁上排队的所有线程。然后自己挂起,直到汽车的属性变为没打过蜡了再醒过来。

class WaxOn implements Runnable {private Car car;public WaxOn(Car c) { car = c; }public void run() {try {while(!Thread.interrupted()) {printnb("Wax On! ");TimeUnit.MILLISECONDS.sleep(200);car.waxed();car.waitForBuffing();}} catch(InterruptedException e) {print("Exiting via interrupt");}print("Ending Wax On task");}
}

抛光机器人和打蜡机器人相反,上来就挂起,直到汽车属性变为打过蜡了才醒过来,然后开始抛光。然后再循环这个过程。

class WaxOff implements Runnable {private Car car;public WaxOff(Car c) { car = c; }public void run() {try {while(!Thread.interrupted()) {car.waitForWaxing();printnb("Wax Off! ");TimeUnit.MILLISECONDS.sleep(200);car.buffed();}} catch(InterruptedException e) {print("Exiting via interrupt");}print("Ending Wax Off task");}
}

利用活动对象模型

“活动对象”模型的处理方法,就是把waxOn()和waxOff()的动作都封装成Callable对象,提交给消息队列,并立即返回一个Future对象。由于使用的SingleThreadExecutor单线程执行器,会按照我们的提交顺序执行。如果我们依次提交 ”打蜡-抛光-打蜡-抛光-打蜡-抛光-… …“,活动对象就会按顺序很好地完成交给它的工作。

public class Exercise42{private static int carCount=0;private static int robotCount=0;private static List<ActiveCarRobot> robots=new ArrayList<ActiveCarRobot>();public class Car{private final int id=++carCount;private boolean waxOn=false;public void waxOn(){if(waxOn){System.out.println("Error, the wax already on!");return;}waxOn=true;}public void waxOff(){if(!waxOn){System.out.println("Error, should waxOn before waxOff!");return;}waxOn=false;}public String toString(){return "Car#"+id;}}public class ActiveCarRobot implements Runnable{private final int id=++robotCount;private final ExecutorService exec=Executors.newSingleThreadExecutor(); //必须是单线程执行器private List<Future<String>> results=new CopyOnWriteArrayList<Future<String>>();private Car car;public ActiveCarRobot(Car c){car=c;robots.add(this);}public String toString(){return "Robot#"+id;}public void run(){for(int i=0;i<10;i++){results.add(waxOn());sleep(10);results.add(waxOff());}showResults();shutdown();}public Future<String> waxOn(){return exec.submit(new Callable<String>(){    //把waxOn的动作封装成一个Callable对象,被提交给消息队列public String call(){sleep(10);car.waxOn();return "    "+car+" wax on by "+ActiveCarRobot.this;}});}public Future<String> waxOff(){return exec.submit(new Callable<String>(){  //把waxOff的动作封装成一个Callable对象,被提交给消息队列public String call(){sleep(10);car.waxOff();return "    "+car+" wax off by "+ActiveCarRobot.this;}});}public void sleep(int time){try{TimeUnit.MILLISECONDS.sleep(time);}catch(InterruptedException ie){System.out.println(this+" interrupted!");}}public void shutdown(){exec.shutdownNow();}public void showResults(){long endAt=System.currentTimeMillis()+5000;while(true){for(Future<String> f:results){if(f.isDone()){try{System.out.println(f.get());}catch(Exception e){System.out.println("Error when reading the results!");}}results.remove(f);}if(System.currentTimeMillis()>=endAt){break;}}}}public static void main(String[] args){Exercise42 test=new Exercise42();ExecutorService exec=Executors.newCachedThreadPool();for(int i=0;i<10;i++){exec.execute(test.new ActiveCarRobot(test.new Car()));}try{TimeUnit.SECONDS.sleep(5);}catch(InterruptedException ie){System.out.println("Test interrupted!");}exec.shutdownNow();}
}

希望对大家有帮助

java并发--活动对象相关推荐

  1. Java并发,volatile+不可变容器对象能保证线程安全么?!

    <Java并发编程实战>第3章原文 <Java并发编程实战>中3.4.2 示例:使用Volatile类型来发布不可变对象 在前面的UnsafeCachingFactorizer ...

  2. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  3. java并发编程实践学习---java的类锁和对象锁

    最近在看Java Concurrent in Practice(java并发编程实践),发现自己对java的线程.锁等机制,理解很肤浅,学习的也不够全面.打算借着这本书,全面的学习下JDK的并发包和一 ...

  4. java函数ao活动对象_[AO] AO全面介绍

    活动对象:一.同步函数被调用时,它会将服务执行完成,然后才返回到其调用处. 异步函数则会在函数调用中提交一个请求,然后马上返回到调用处,但该请求会迟些才会完成.在请求完成之前,调用者可以继续执行其它的 ...

  5. Java并发编程(五):Java线程安全性中的对象发布和逸出

    发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外 ...

  6. java 如何知道对象是否被修改过_Java 并发编程:AQS 的原子性如何保证

    当我们研究AQS框架时(对于AQS不太熟知可以先阅读<什么是JDK内置并发框架AQS>,会发现AbstractQueuedSynchronizer这个类很多地方都使用了CAS操作.在并发实 ...

  7. java火箭应用_从火箭发场景来学习Java多线程并发闭锁对象

    原标题:从火箭发场景来学习Java多线程并发闭锁对象 从火箭发场景来学习Java多线程并发闭锁对象 倒计时器场景 在我们开发过程中,有时候会使用到倒计时计数器.最简单的是:int size = 5; ...

  8. java并发常量_Java并发编程-常量对象(七)

    在创建后状态不再发生改变的对象称作常量对象(Immutable Objects).常量对象其可靠性使其广泛地用作开发简单可靠代码的策略.常量对象在开发并发程序中非常有用.由于创建后不能被改变状态,它们 ...

  9. java单线程共享,「Java并发编程实战」之对象的共享

    前言 本系列博客是对<Java并发编程实战>的一点总结,本篇主要讲解以下几个内容,内容会比较枯燥.可能大家看标题不能能直观的感受出到底什么意思,这就是专业术语,哈哈,解释下,术语(term ...

  10. java 闭锁_从火箭发场景来学习Java多线程并发闭锁对象

    从火箭发场景来学习Java多线程并发闭锁对象 倒计时器场景 在我们开发过程中,有时候会使用到倒计时计数器.最简单的是:int size = 5; 执行后,size-这种方式来实现.但是在多线程并发的情 ...

最新文章

  1. python3.7新功能_2018-11-08安装Python3.7详解
  2. 如何选择版本控制系统之二
  3. 领先微软技术咨询公司招聘技术人员
  4. [开源]FreeSCADA的通道数据与控件属性关联以及自动刷新机制研究
  5. android menu xml 属性,Android中Menu类型及常见属性说明
  6. iOS UIButton文字和图片间距随意调整
  7. 业界最强!阿里“平头哥”首款芯片发布:应用于5G、自动驾驶等领域
  8. Python2.7和3.6之间的区别
  9. 10分钟搞定kettle源码部署
  10. tensorflow之add_to_collection
  11. Python + Selenium 自动发布文章(一):开源中国
  12. fastdfs 集群配置
  13. CHM格式打不开解决方案
  14. 面包板的使用-----看板子反面即可
  15. 管理者要做木匠,不要做医生”。木匠眼里,没有废料,每一块木材都有它的作用;而在医生眼里,没有完全健康的人,每个人都是病人
  16. html css网页代码,源码附上
  17. 网络教育计算机和英语难度怎样,网络教育统考大学英语b难吗?
  18. unity3d RTS即时战略 鼠标点选主角移动到点击地面位置 代码
  19. python dict添加key 和value_python迭代dict的key和value的方法
  20. 浅谈数据标注平台运营模式

热门文章

  1. java 伊甸园_离伊甸园仅一步之遥
  2. 狂热分子——码头工人的哲学沉思录
  3. oracle的同义词删不掉,oracle 删除同义词
  4. 苹果CMS采集参数全自动采集教程
  5. 兼容IE8的多文件上传实现
  6. 怎么把淘宝宝贝分享到微信朋友圈
  7. 小火狐进化_口袋妖怪xy三主进化详细介绍
  8. Windows Server2012搭建邮件服务器
  9. CentOS 7 搭建邮件服务器搭建(postfix+dovecot)
  10. 彩信 添加 html,彩信接口 | 微米-中国领先的短信彩信接口平台服务商