(转载; http://blog.csdn.net/chenleixing/article/details/44044243

Java并发编程的4种风格:Threads,Executors,ForkJoin和Actors;这里为了完成下面的任务,用四种方式来实现。

任务:

实现一个方法,它接收一条消息和一组字符串作为参数,这些字符串与某个搜索引擎的查询页面对应。对每个字符串,这个方法发出一个http请求来查询消息,并返回第一条可用的结果,越快越好。

方法一:  Threads

   AtomicReference:
  提供了引用变量的读写原子性操作(也可以保证可见性) ;

线程的接口相当简明,你只需要提供一个Runnable,调用.start()开始计算。没有现成的API来结束线程,你需要自己来实现,通过类似boolean类型的标记来通讯

package com.ibm.multithread;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference; public class PureThread {
static String getFirstResult(String question, List<String> engines) {
AtomicReference<String> result = new AtomicReference<>();
for (String base : engines) {
String url = base + question; new Thread(() -> {
result.compareAndSet(null, "999999999999");
}).start();
} while (result.get() == null);
return result.get(); }
}

自己管理线程的最大劣势是,你很容易过分的关注线程的数量。线程是很昂贵的对象,创建它们需要耗费大量的内存和时间。这是一个矛盾,线程太少,你不能获得良好的并发性;线程太多,将很可能导致内存问题,调度也变得更复杂。

方法二:
    ExecutorCompletionService

  ExecutorService和CompletionService区别:
ExecutorService:一直习惯自己维护一个list保存submit的callable task所返回的Future对象。在主线程中遍历这个list并调用Future的get()方法取到Task的返回值。
CompletionService:在很多地方会看到一些代码通过CompletionService包装ExecutorService,然后调用其take()方法去取Future对象。
这两者最主要的区别在于submit的task不一定是按照加入自己维护的list顺序完成的。从list中遍历的每个Future对象并不一定处于完成状态,这时调用get()方法就会被阻塞住,如果系统是设计成每个线程完成后就能根据其结果继续做后面的事,这样对于处于list后面的但是先完成的线程就会增加了额外的等待时间。
而CompletionService的实现是维护一个保存Future对象的BlockingQueue。只有当这个Future对象状态是结束的时候,才会加入到这个Queue中,take()方法其实就是Producer-Consumer中的Consumer。它会从Queue中取出Future对象,如果Queue是空的,就会阻塞在那里,直到有完成的Future对象加入到Queue中。
所以,先完成的必定先被取出。这样就减少了不必要的等待时间。
jdk 自带线程池结果管理器:ExecutorCompletionService。它将BlockingQueue 和Executor 封装起来。然后使用ExecutorCompletionService.submit()方法提交任务。

package com.ibm.multithread;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors; public class ExecutorExample {
static String getFirstResult(String question, List<String> engines) {
ExecutorCompletionService<String> service = new ExecutorCompletionService<>(Executors.newFixedThreadPool(4)); for (String base : engines) {
String url = base + question;
service.submit(() -> {return "fdsfdsfsd";});
} try {
return service.take().get();
}
catch(InterruptedException| ExecutionException e) {
return null;
}
}
}

如果你需要精确的控制程序产生的线程数量,以及它们的精确行为,那么executor和executor服务将是正确的选择。例如,需要仔细考虑的一个重要问题是,当所有线程都在忙于做其他事情时,需要什么样的策略?增加线程数量或者不做数量限制?把任务放入到队列等待?如果队列也满了呢?无限制的增加队列大小?

感谢JDK,已经有很多配置项回答了这些问题,并且有着直观的名字,例如上面的Executors.newFixedThreadPool(4)。

线程和服务的生命周期也可以通过选项来配置,使资源可以在恰当的时间关闭。唯一的不便之处是,对新手来说,配置选项可以更简单和直观一些。然而,在并发编程方面,你几乎找不到更简单的了。

总之,对于大型系统,我个人认为使用executor最合适。

方法三:
   forkjoin:
 Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。
Fork/Join框架要完成两件事情:
   (1).任务分割:首先Fork/Join框架需要把大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割
   (2).执行任务并合并结果:分割的子任务分别放到双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都放在另外一个队列里,
启动一个线程从队列里取数据,然后合并这些数据。
Optional: 是Java8提供的为了解决null安全问题的一个API:
public static String getName(User u) {
if (u == null)
return "Unknown";
return u.name;
}

public static String getName(User u) {
return Optional.ofNullable(u)
.map(user->user.name)
.orElse("Unknown");
}

map: 是按照给定规则对流的每一个元素进行一种变化(映射),得到另外的序列。

paralle: Java8的paralleStream用fork/join框架提供了并发执行能力;

Java 8中加入了并行流,从此我们有了一个并行处理集合的简单方法。它和lambda一起,构成了并发计算的一个强大工具。

package com.ibm.multithread;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference; public class ForkJoinPool {
static String getFirstResult(String question, List<String> engines) {
Optional<String> result = engines.stream().parallel().map((base) -> {
String url = base + question;
return "fdsfsdf";
}).findAny(); return result.get(); } public static String getName(User u) {
return Optional.ofNullable(u)
.map(user->user.name)
.orElse("Unknown");
} class User {
private String name;
private String fljdsaljf;
}
}

方法四:actor:

package com.ibm.multithread.ActorTest;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props; import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; public class ActorTest {
public static void main(String[] args) {
ActorTest actor = new ActorTest();
actor.getFirstResultActors("", Arrays.asList("aa", "bb"));
} public String getFirstResultActors(String question, List<String> engines) {
ActorSystem system = ActorSystem.create("Search");
AtomicReference<String> result = new AtomicReference<>(); final ActorRef q = system.actorOf(Props.create(Querier.class, question, engines, result)); q.tell(new Object(), ActorRef.noSender());
while (result.get() == null)
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return result.get();
}
}
package com.ibm.multithread.ActorTest;

public class Message {

    Message(String url) {this.url = url;}
private String name;
private String url;
}
package com.ibm.multithread.ActorTest;

import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedActor; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; class Querier extends UntypedActor {
private String question;
private List<String> engines;
private AtomicReference<String> result;
public Querier(String question, List<String> engines, AtomicReference<String> result) {
this.question = question;
this.engines = engines;
this.result = result;
} @Override
public void onReceive(Object message) throws Exception {
if (message instanceof Result) {
result.compareAndSet(null,((Result) message).html);
getContext().stop(self());
} else {
for (String base : engines) {
String url = base + question;
ActorRef fetcher = this.getContext().actorOf(Props.create(UrlFetcher.class),"fetcher-" + base.hashCode());
Message m = new Message(url);
fetcher.tell(m, self());
}
}
}
}
package com.ibm.multithread.ActorTest;

public class Result {
String html;
Result(String html) {
this.html = html;
}
}
package com.ibm.multithread.ActorTest;

import akka.actor.UntypedActor;

import java.util.concurrent.TimeUnit;

class UrlFetcher extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof Message) {
Message work = (Message) message;
String result = "result...";
TimeUnit.SECONDS.sleep(1);
getSender().tell(new Result(result), getSelf());
} else {
unhandled(message);
}
}
}

简短地说,在actor模型中,你把一切都看做是一个actor。一个actor是一个计算实体,就像上面第一个例子中的线程,它可以从其他actor那里接收消息,因为一切都是actor。

在应答消息时,它可以给其他actor发送消息,或者创建新的actor并与之交互,或者只改变自己的内部状态。

相当简单,但这是一个非常强大的概念。生命周期和消息传递由你的框架来管理,你只需要指定计算单元是什么就可以了。另外,actor模型强调避免全局状态,这会带来很多便利。你可以应用监督策略,例如免费重试,更简单的分布式系统设计,错误容忍度等等。

三 akka学习 actor的例子的更多相关文章

  1. 二 Akka学习 - actor介绍

    一个actorSystem 是一个重量级的结构.它会分配N个线程.所以对于每一个应用来说只用创建一个ActorSystem. Actor是种可怜的“生物”,它们不能独自存活.Akka中的每一个Acto ...

  2. 一 Akka学习 - actor

    (引用 http://shiyanjun.cn/archives/1168.html) 一: 什么是Akka? Akka是JAVA虚拟机JVM平台上构建高并发.分布式和容错应用的工具包和运行时,是一个 ...

  3. 2014.8.12-AKKA和Actor model 分布式开发环境学习小结

    学习使用AKKA 断断续续有一年了. 眼下还是习惯用java来写akka以下的程序.对于原生的scala还是没有时间和兴趣去学习它. 毕竟学习一门语言须要兴趣和时间的. AKKA学习资源还是不算丰富. ...

  4. (转)Akka学习笔记(二):Actor Systems

    Akka学习笔记(二):Actor Systems 图中表示的是一个Actor System,它显示了在这个Actor System中最重要实体之间的关系. 什么是actor,是一个封装了状态和行为的 ...

  5. AKKA学习(一)

    AKKA简介 什么是AKKA Akka是一个由Scala编写的,能兼容Sacala和JAVA的,用于编写高可用和高伸缩性的Actor模型框架.它基于了事件驱动的并发处理模式,性能非常的高,并且有很高的 ...

  6. 20145304 Java第三周学习报告

    20145304 <Java程序设计>第三周学习总结 教材学习内容总结 1.定义类: 类定义时使用class关键词,建立实例要使用new关键词. 代码如下: /*定义类 书上例子 衣服的型 ...

  7. 20145330《Java程序设计》第三周学习总结

    20145330 <Java程序设计>第三周学习总结 第三周知识的难度已经逐步上升,并且一周学习两章学习压力也逐渐加大,需要更高效率的来完成学习内容,合理安排时间. 类与对象 对象(Obj ...

  8. 20145337《Java程序设计》第三周学习总结

    20145337 <Java程序设计>第三周学习总结 教材学习内容总结 类与对象 类与对象的关系:要产生对象必须先定义类,类是对象的设计图,对象是类的实例.我觉得在视频中对类与对象关系的描 ...

  9. AKKA学习笔记

    AKKA学习笔记总结 01. AKKA 1. 介绍: Akka基于Actor模型,提供了一个用于构建可扩展的(Scalable).弹性的(Resilient).快速响应的(Responsive)应用程 ...

随机推荐

  1. 从 零开始 无差错 装好nginx+PHP

    由于这两天 一直有人追问 nginx为何报错,为何php没装好啥的,大多原因是 : 1.编译与yum混合安装,导致很多包的路径不对,进而报错 2.yum源比较旧,导致 与新版本的php不匹配 3.安装 ...

  2. activiti--5 -----------------Activiti 工作流 流程各个步骤所涉及到的表

    ACT_RE_*: 'RE'表示repository. 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等). ACT_RU_*: 'RU'表示runtime. 这些运行时的表,包含流程实例 ...

  3. memcached 不同客户端的问题

    摘要: memcached-java客户端调用get方法获取数据失败 主要演示一下在memcached服务器端set数据之后,在客户端调用java api获取数据.不过此过程如果不慎会读取数据失败. ...

  4. Centos下MySQL数据库主从双向同步配置

    MYSQL支持单向.异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器.主服务器将更新写入二进制日志文件,并维护日志文件的一个索引以跟踪日志循环.当一个从服务器连接到主服务 ...

  5. Data Structure Array: Given an array of of size n and a number k, find all elements that appear more than n/k times

    http://www.geeksforgeeks.org/given-an-array-of-of-size-n-finds-all-the-elements-that-appear-more-tha ...

  6. Python 注释和中文乱码

    Python 注释分为三种: 1.单行注释:# 2.多行注释:前后3个单引号,或者三个双引号: 如:''' 多行注释 ''', """或者 多行注释 '"&qu ...

  7. nginx Unit 服务器

    转自: https://github.com/nginx/unit/pull/18/ 感谢: https://www.v2ex.com/t/389528 English 简体中文 繁體中文 NGINX ...

  8. bzoj 3038: 上帝造题的七分钟2 线段树||hdu 4027

    3038: 上帝造题的七分钟2 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1066  Solved: 476[Submit][Status][Dis ...

  9. php设计模式课程---4、观察者模式的好处是什么

    php设计模式课程---4.观察者模式的好处是什么 一.总结 一句话总结: 方便选择之后去控制监听的板块数:比如选择男士之后,我可以决定监听广告里面的第二和第三板块. 1.为什么有观察者模式? 错误理 ...

  10. django1.8.3搭建博客——1

    系统:elementary os python 2.7.6 django 1.8.3 1.安装django 先安装pip   sudo apt-get install python3-pip 安装dj ...