将带有Executor服务的Java多线程迁移到Akka
我只是想知道是否有可能将用Java的Executor服务编写的旧多线程代码替换为Akka。对此我没有什么疑问将带有Executor服务的Java多线程迁移到Akka,java,multithreading,akka,Java,Multithreading,Akka,我只是想知道是否有可能将用Java的Executor服务编写的旧多线程代码替换为Akka。对此我没有什么疑问 Is akka actor runs in their own thread? How Threads will be assigned for the Actors ? What are the pros and cons of migration of it is possible? 目前我使用固定线程池进行多线程,并提交一个可调用的线程池 示例代码 public class
Is akka actor runs in their own thread?
How Threads will be assigned for the Actors ?
What are the pros and cons of migration of it is possible?
目前我使用固定线程池进行多线程,并提交一个可调用的线程池
示例代码
public class KafkaConsumerFactory {
private static Map<String,KafkaConsumer> registry = new HashMap<>();
private static ThreadLocal<KafkaConsumer> consumers = new ThreadLocal<KafkaConsumer>(){
@Override
protected KafkaConsumer initialValue() {
return new KafkaConsumer(createConsumerConfig());
}
};
static {
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
registry.forEach((tid,con) -> {
try{
con.close();
} finally {
System.out.println("Yes!! Consumer for " + tid + " is closed.");
}
});
}
});
}
private static Properties createConsumerConfig() {
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "newcon-grp5");
props.put("key.deserializer", StringDeserializer.class.getName());
props.put("value.deserializer", KafkaKryoSerde.class.getName());
return props;
}
public static <K,V> KafkaConsumer<K,V> createConsumer(){
registry.put(Thread.currentThread().getName(),consumers.get());
return consumers.get();
}
}
公共级卡夫卡消费工厂{
私有静态映射注册表=new HashMap();
私有静态ThreadLocal使用者=新ThreadLocal(){
@凌驾
受保护的Kafka消费者初始值(){
返回新的KafkaConsumer(createConsumerConfig());
}
};
静止的{
Runtime.getRuntime().addShutdownHook(新线程(){
@凌驾
公开募捐{
registry.forEach((tid,con)->{
试一试{
con.close();
}最后{
System.out.println(“是!!“+tid+”的消费者关闭”);
}
});
}
});
}
私有静态属性createConsumerConfig(){
Properties props=新属性();
put(“bootstrap.servers”,“localhost:9092”);
道具出售(“group.id”、“newcon-grp5”);
put(“key.deserializer”,StringDeserializer.class.getName());
put(“value.deserializer”,KafkaKryoSerde.class.getName());
返回道具;
}
公共静态KafkanConsumer createConsumer(){
registry.put(Thread.currentThread().getName(),consumers.get());
返回消费者。get();
}
}
/////////////////////////////////////////////////////////
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
public class KafkaNewConsumer {
public static int MAX_THREADS = 10;
private ExecutorService es = null;
private boolean stopRequest = false;
public static void main(String[] args){
KafkaNewConsumer knc = new KafkaNewConsumer();
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run(){
knc.es.shutdown();
try {
knc.es.awaitTermination(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException ignored) {
}finally {
System.out.println("Finished");
}
}
});
knc.consumeTopic("rtest3",knc::recordConsuemer);
}
public void recordConsuemer(ConsumerRecord<?,?> record){
String result = new StringJoiner(": ")
.add(Thread.currentThread().getName())
.add("ts").add(String.valueOf(record.timestamp()))
.add("offset").add(String.valueOf(record.offset()))
.add("data").add(String.valueOf(record.value()))
.add("value-len").add(String.valueOf(record.serializedValueSize()))
.toString();
System.out.println(result);
}
public void consumeTopic(String topicName, Consumer<ConsumerRecord<?,?>> fun){
KafkaConsumer con= KafkaConsumerFactory.createConsumer();
int paritions = con.partitionsFor(topicName).size();
int noOfThread = (MAX_THREADS < paritions) ? MAX_THREADS :paritions;
es = Executors.newFixedThreadPool(noOfThread);
con.close();
for(int i=0;i<noOfThread;i++){
es.submit(()->{
KafkaConsumer consumer = KafkaConsumerFactory.createConsumer();
try{
while (!stopRequest){
consumer.subscribe(Collections.singletonList(topicName));
ConsumerRecords<?,?> records = consumer.poll(5000);
records.forEach(fun);
consumer.commitSync();
}
}catch(Exception e){
e.printStackTrace();
} finally {
consumer.close();
}
});
}
}
}
import org.apache.kafka.clients.consumer.ConsumerRecord;
导入org.apache.kafka.clients.consumer.ConsumerRecords;
导入org.apache.kafka.clients.consumer.KafkaConsumer;
导入org.apache.kafka.common.TopicPartition;
导入org.apache.kafka.common.serialization.StringDeserializer;
导入java.util.*;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.TimeUnit;
导入java.util.function.Consumer;
公共类KafkaNewConsumer{
公共静态int MAX_线程=10;
私有执行者服务=null;
私有布尔stopRequest=false;
公共静态void main(字符串[]args){
KafkaNewConsumer knc=新的KafkaNewConsumer();
Runtime.getRuntime().addShutdownHook(新线程(){
@凌驾
公开募捐{
knc.es.shutdown();
试一试{
knc.es.等待终止(500,时间单位毫秒);
}捕获(InterruptedException被忽略){
}最后{
系统输出打印项次(“完成”);
}
}
});
consumertopic(“rtest3”,knc::recordConsuemer);
}
公共作废记录消费者(消费者记录记录){
字符串结果=新的StringJoiner(“:”)
.add(Thread.currentThread().getName())
.add(“ts”).add(String.valueOf(record.timestamp()))
.add(“偏移量”).add(String.valueOf(record.offset()))
.add(“数据”).add(String.valueOf(record.value()))
.add(“value len”).add(String.valueOf(record.serializedValueSize()))
.toString();
系统输出打印项次(结果);
}
public void consumertopic(字符串topicName,Consumer records=Consumer.poll(5000);
记录。forEach(乐趣);
consumer.commitSync();
}
}捕获(例外e){
e、 printStackTrace();
}最后{
consumer.close();
}
});
}
}
}
我浏览了一些网络教程,其中一些直接得出结论
演员非常优秀,比传统的线程速度更快
但没有解释它如何比线程更快?
我尝试了一些示例Akka(来自activator的Akka示例)代码,并在所有参与者中打印了Thread.currentThread.getName,发现创建了名为(helloakka-Akka.actor.default-dispatcher-X)的不同调度程序线程
但是怎么做呢?谁在创建这些线程?它们的配置在哪里?线程和参与者之间的映射关系是什么?
每次我发送消息时,Akka会创建新线程吗?或者在内部使用线程池? 若我需要100个线程来并行执行某个任务的某些部分,我是否需要创建100个参与者并向每个参与者发送一条消息?或者我需要创建一个actor并将100条消息放入它的队列中,它将被分成100个线程。
真正令人困惑的迁移到actor系统对于基于executor的系统来说不是一项小任务,但它是可以完成的。它要求你重新思考你设计系统的方式,考虑演员的影响。例如,在线程体系结构中,您为业务流程创建一些处理程序,将其放入可运行状态,让它在线程上执行操作。这对于一个演员范例来说是完全不合适的。您必须重新设计您的系统,以处理消息传递和使用消息来调用任务。此外,您还必须改变对业务流程的思考方式,从命令式方法转变为基于消息的方法。举例来说,考虑购买产品的简单任务。我假设你知道如何在遗嘱执行人身上做这件事。在actor系统中,您可以执行以下操作: (采购产品)->UserActor->(BillCredit Card)->CCProcessing Actor->(采购批准并计费的项目)->库存经理->。。。等等 在每个阶段,括号中是发送给相关参与者的异步消息,该参与者执行业务逻辑,然后将消息转发给流程中的下一个参与者 现在这只是一个开始