前面一段时间,瞄了一下《七周七并发模型》。感叹还是有很多语言不会,导致有的章节现在还没法看。但是,Actor并发模型还是给我留下了比较深的印象,因为它适合应用于分布式架构,而且具有很好的容错性。和Actor-based相对应的模型就是Task-based。
Actor-based与Task-based的含义
Actor-based和Task-based的含义要从”计算“的内涵说起,”计算“包含两个要素:
- 用来进行工作的线程
- 进行工作所需的信息
因为,线程主动地对信息进行计算处理,所以我们把线程作为计算的“主体”,把信息作为计算的“客体”。对应到并发模型中,Actor-based模型注重主体,而Task-based注重客体。
Task-based模式的思想与实现
在Task-based模式中,工作线程之间通过对”客体“的同步操作,并发地完成计算任务。常见的情况下,各个线程引用同一个信息客体,而且所谓的”通信“就是直接调用信息客体类的方法。这种设计模式的主要关注点在于”信息客体“的设计,计算工作的核心部分在”信息客体“的方法中完成。而线程主体只需要调用对应”客体“的方法即可。一个典型的Task-based模式的例子如下:
PriceInfo.java
package ReadWriteLock;
import java.util.concurrent.locks.*;
public class PriceInfo {
private double price1;
private double price2;
private ReadWriteLock lock;
public PriceInfo() {
price1 = 1.0;
price2 = 2.0;
lock = new ReentrantReadWriteLock();
}
public double getPrice1() {
lock.readLock().lock();
double value = price1;
lock.readLock().unlock();
return value;
}
public double getPrice2() {
lock.readLock().lock();
double value = price2;
lock.readLock().unlock();
return value;
}
public void setPrice(double price1, double price2) {
lock.writeLock().lock();
this.price1 = price1;
this.price2 = price2;
lock.writeLock().unlock();
}
}
Reader.java
package ReadWriteLock;
public class Reader implements Runnable{
private PriceInfo priceInfo;
public Reader(PriceInfo priceInfo) {
this.priceInfo = priceInfo;
}
@Override
public void run() {
for(int i=0; i <10; i++) {
System.out.printf("%s: price 1:%f\n", Thread.currentThread().getName(), priceInfo.getPrice1());
System.out.printf("%s: price 2:%f\n", Thread.currentThread().getName(), priceInfo.getPrice2());
}
}
}
Writer.java
package ReadWriteLock;
public class Writer implements Runnable{
private PriceInfo priceInfo;
public Writer(PriceInfo priceInfo) {
this.priceInfo = priceInfo;
}
@Override
public void run() {
for(int i=0; i<3; i++) {
System.out.printf("Writer: Attempt to modify the prices.\n");
priceInfo.setPrice(Math.random()*10, Math.random()*8);
System.out.printf("Writer: Prices has been modified.\n");
try {
Thread.sleep(2);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
Main.java
package ReadWriteLock;
public class Main {
public static void main(String[] args) {
PriceInfo priceInfo = new PriceInfo();
Reader readers[] = new Reader[5];
Thread threadsReader[] = new Thread[5];
for(int i = 0; i<5; i++){
readers[i] = new Reader(priceInfo);
threadsReader[i] = new Thread(readers[i]);
}
Writer writer = new Writer(priceInfo);
Thread threadWriter = new Thread(writer);
for(int i=0; i<5; i++)
threadsReader[i].start();
threadWriter.start();
}
}
Actor-based模式的思想与实现
在Actor-based模式中,线程的作用更加重要,与Task-based模式中通过方法调用的“消息传递”方式相比,Actor-based的消息传递显得更货真价实。Actor-based模式中,客户端方法的调用(invocation)与服务端方法的执行(execution)是分离的,它们之间的联系被抽象为通信。这里的通信可以是线程之间的通信,也可以是机器之间的通信。这就是Actor模式适应于分布式架构的原因。下面的代码片段来自一个典型的使用Actor模式的消费者线程:
public class SchedulerThread extends Thread{
private final ActivationQueue queue;
public SchedulerThread(ActivationQueue queue) {
this.queue = queue;
}
public void invoke(MethodRequest request) {
queue.putRequest(request);
}
public void run() {
while(true) {
MethodRequest request = queue.takeRequest();
request.execute();
}
}
}
其实在具体的应用中,这两种模式常常是共存的。个人感觉,面向线程与面向信息各有优劣吧!
发表回复