Actor模型
Actor模型
Actor模型本质上是一种计算模型,基本的计算单元称为Actor,换言之,在Actor模型中,所有的计算都是在Actor中执行的。在面向对象编程里面,一切都是对象;在Actor模型里,一切都是Actor,并且Actor之间是完全隔离的,不会共享任何变量。当看到“不共享任何变量”的时候,相信你一定会眼前一亮,并发问题的根源就在于共享变量,而Actor模
型中Actor之间不共享变量,那用Actor模型解决并发问题,一定是相当顺手。的确是这样,所以很多人就把Actor模型定义为一种并发计算模型。其实Actor模型早在1973年就被提出来了,只是直到最近几年才被广泛关注,一个主要原因就在于它是解决并发问题的利器,而最近几年随着多核处理器的发展,并发问题被推到了风口浪尖上。但是Java语言本身并不支持Actor模型,所以如果你想在Java语言里使用Actor模型,就需要借助第三方类
库,目前能完备地支持Actor模型而且比较成熟的类库就是Akka了。
Actor模型的另一个好处是可以消除共享状态,因为Actor每次只能处理一条消息,所以Actor内部可以安全的处理状态,而不用考虑锁机制。
缺点
当所有的逻辑都跑在Actor中的时候,很难掌握Actor的粒度,稍有不慎就可能造成系统中Actor个数爆炸的情况。另外,当必须共享的数据或者状态很难避免使用锁,由于Actor可能会阻塞自己,但Actor不应该阻塞它运行的线程。
Demo 示例
引入pom依赖
<!-- 配置akka依赖-->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.3.11</version>
</dependency>
看下面的Demo
我们对未加锁的counter使用Actor进行累加,总共是四个线程,每个线程加100000次,结果就是400000次,符合
package xwb.actor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author 17912
* @Date 2021-9-13-013 9:45:20
* @Version 1.0
*/
//累加器
public class CounterActor extends UntypedActor {
private int counter = 0;
@Override
public void onReceive(Object message) {
//如果接收到的消息是数字类型,执⾏累加操作,
//否则打印counter的值
if (message instanceof Number) {
counter = ((Number) message).intValue();
//System.out.println(Thread.currentThread().getName());
} else {
System.out.println(message ":" counter);
}
}
static int threadCount = 4, time = 100000;
static CountDownLatch countDownLatch = new CountDownLatch(threadCount * time);
public static void main(String[] args) throws InterruptedException {
//创建Actor系统
ActorSystem system = ActorSystem.create("HelloSystem");
//4个线程⽣产消息
ExecutorService es = Executors.newFixedThreadPool(threadCount);
//创建CounterActor
ActorRef counterActor =
system.actorOf(Props.create(CounterActor.class));
long startTime = System.currentTimeMillis();
//⽣产4*100000个消息
AtomicInteger atomicInteger = new AtomicInteger(0);
for (int i = 0; i < threadCount; i ) {
es.execute(() -> {
for (int j = 0; j < time; j ) {
//使用原子类
atomicInteger.incrementAndGet();
//counterActor.tell(1, ActorRef.noSender());
countDownLatch.countDown();
}
});
}
//关闭线程池
countDownLatch.await();
System.out.println("耗时:" (System.currentTimeMillis() - startTime));
//counterActor.tell("结束 打印值", ActorRef.noSender());
System.out.println(atomicInteger.get());
es.shutdown();
//等待CounterActor处理完所有消息
// Thread.sleep(1000);
//打印结果
//关闭Actor系统
system.shutdown();
}
}
使用原子类之后我惊了,还没有AtomicInteger效率高,啥呀
AtomicInteger:113ms
Actor:400ms
消息和对象方法的区别
在没有计算机的时代,异地的朋友往往是通过写信来交流感情的,但信件发出去之后,也许会在寄送过程中弄丢了,也有可能寄到后,对方一直没有时间写回信……这个时候都可以让邮局“背个锅”,不过无论如何,也不过是重写一封,生活继续。Actor中的消息机制,就可以类比这现实世界里的写信。Actor内部有一个邮箱(Mailbox),接收到的消息都是先放到邮箱里,如果邮箱里有积压的消息,那么新收到的消息就不会马上得到处理,也正是因为Actor使用单线程处理消息,所以不会出现并发问题。你可以把Actor内部的工作模式想象成只有一个消费者线程的生产者-消费者模式。所以,在Actor模型里,发送消息仅仅是把消息发出去而已,接收消息的Actor在接收到消息后,也不一定会立即处理,也就是说Actor中的消息机制完全是异步的。而调用对象方法,实际上是同步的,对象方法return之前,调用方会一直等待。除此之外,调用对象方法,需要持有对象的引用,所有的对象必须在同一个进程中。而在Actor中发送消息,类似于现实中的写信,只需要知道对方的地址就可以,发送消息和接收消息的Actor可以不在一个进程中,也可以不在同一台机器上。因此,Actor模型不但适用于并发计算,还适用于分布式计算。
参考文献
极客时间高并发编程实战
Actor模型
Actor模式对比同步方式
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfhgbib
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01