有些东西其实就是一层纸,当你偶然穿透的时候,就会豁然开朗,眼前一亮。
以前总是对一些并发测试不感冒,有时候觉得我从下手的感觉。但是不自己亲自测试一把又觉得不放心,于是总是在Thread里面来来回回的修改,
在run方法中做这个中修改,总是乱乱的感觉。今天突然从别人的代码中顿悟了,体系终于明朗了。
我以构建高效且可伸缩的结果缓存为例,希望给大家启示。
// 定义泛型计算接口
public interface Computable<A, W> {
W compute(A arg) throws InterruptedException;
}
// 实现一个具体类型的计算接口
public class ExpensiveFunction implements Computable<String, BigInteger> {
public BigInteger compute(String arg) {
for (int i = 0; i < 1000000000; i++);
System.out.println(Thread.currentThread().getName() + "計算中......");
return new BigInteger(arg);
}
}
// 泛型计算接口具体实现
public class Memoizer<A, W> implements Computable<A, W> {
private final ConcurrentHashMap<A, Future<W>> cache = new ConcurrentHashMap<A, Future<W>>();
private final Computable<A, W> com;
public Memoizer(Computable<A, W> c) {
this.com = c;
}
@Override
public W compute(final A arg) throws InterruptedException {
Future<W> f = cache.get(arg);
if (f == null) {
Callable<W> eval = new Callable<W>() {
@Override
public W call() throws Exception {
return com.compute(arg);
}
};
FutureTask<W> ft = new FutureTask<W>(eval);
f = cache.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
ft.run();
}
}
try {
return f.get();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
throw new InterruptedException();
}
}
}
// 说了这么多,其实并发测试才是关键,条理的实现,优雅明了
// 在相应的开发中,往往演变为util类
public class ComputeClient {
private static ExpensiveFunction ef = new ExpensiveFunction();
private static final Memoizer<String, BigInteger> memoizer = new Memoizer<String, BigInteger>(ef);
public static BigInteger compute(String arg) throws InterruptedException {
return memoizer.compute(arg);
}
}
// 模拟一个线程,你可以是servlet,action,调用开始
public class CacheThread extends Thread {
private String arg;
public MyCacheThread(String arg) {
this.arg = arg;
}
public void run() {
try {
System.out.println(ComputeClient.compute(arg));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 大规模并发开始,走起来,小伙伴们。
// 如果想要同时大规模启动线程,参照我以前的关于闭锁来实现并发测试
public class CacheDemo {
/**
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
if (i == 0 || i == 1) {
new CacheThread(String.valueOf(i + 2)).start();
} else {
new CacheThread(String.valueOf(i)).start();
}
}
}
}
纸上得来终觉浅,绝知此事要躬行。学习,coding,test,一步步走向体系,加油!
以前总是对一些并发测试不感冒,有时候觉得我从下手的感觉。但是不自己亲自测试一把又觉得不放心,于是总是在Thread里面来来回回的修改,
在run方法中做这个中修改,总是乱乱的感觉。今天突然从别人的代码中顿悟了,体系终于明朗了。
我以构建高效且可伸缩的结果缓存为例,希望给大家启示。
// 定义泛型计算接口
public interface Computable<A, W> {
W compute(A arg) throws InterruptedException;
}
// 实现一个具体类型的计算接口
public class ExpensiveFunction implements Computable<String, BigInteger> {
public BigInteger compute(String arg) {
for (int i = 0; i < 1000000000; i++);
System.out.println(Thread.currentThread().getName() + "計算中......");
return new BigInteger(arg);
}
}
// 泛型计算接口具体实现
public class Memoizer<A, W> implements Computable<A, W> {
private final ConcurrentHashMap<A, Future<W>> cache = new ConcurrentHashMap<A, Future<W>>();
private final Computable<A, W> com;
public Memoizer(Computable<A, W> c) {
this.com = c;
}
@Override
public W compute(final A arg) throws InterruptedException {
Future<W> f = cache.get(arg);
if (f == null) {
Callable<W> eval = new Callable<W>() {
@Override
public W call() throws Exception {
return com.compute(arg);
}
};
FutureTask<W> ft = new FutureTask<W>(eval);
f = cache.putIfAbsent(arg, ft);
if (f == null) {
f = ft;
ft.run();
}
}
try {
return f.get();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
throw new InterruptedException();
}
}
}
// 说了这么多,其实并发测试才是关键,条理的实现,优雅明了
// 在相应的开发中,往往演变为util类
public class ComputeClient {
private static ExpensiveFunction ef = new ExpensiveFunction();
private static final Memoizer<String, BigInteger> memoizer = new Memoizer<String, BigInteger>(ef);
public static BigInteger compute(String arg) throws InterruptedException {
return memoizer.compute(arg);
}
}
// 模拟一个线程,你可以是servlet,action,调用开始
public class CacheThread extends Thread {
private String arg;
public MyCacheThread(String arg) {
this.arg = arg;
}
public void run() {
try {
System.out.println(ComputeClient.compute(arg));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 大规模并发开始,走起来,小伙伴们。
// 如果想要同时大规模启动线程,参照我以前的关于闭锁来实现并发测试
public class CacheDemo {
/**
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
if (i == 0 || i == 1) {
new CacheThread(String.valueOf(i + 2)).start();
} else {
new CacheThread(String.valueOf(i)).start();
}
}
}
}
纸上得来终觉浅,绝知此事要躬行。学习,coding,test,一步步走向体系,加油!