前面一段时间,瞄了一下《七周七并发模型》。感叹还是有很多语言不会,导致有的章节现在还没法看。但是,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(); } } }
其实在具体的应用中,这两种模式常常是共存的。个人感觉,面向线程与面向信息各有优劣吧!
发表评论