在controller的action中使用锁和线程 要特别小心,最好不要使用。
这是由于play在处理多个请求时实际上是复用的一个线程,而不像struts之类的框架,每个请求一个线程一个对象。
所以如下例子中
public class TestC extends Controller{
public static void t(){
synchronized(TestC.class){
Thread.sleep(10000);
}
ok();
}
public static void t2(){
ok();
}
}
你会发现 不仅是 路由 t 的请求被阻塞,就连t2的请求也被阻塞了,play框架在处理所有请求时 只使用了若干个有限的线程进行线程复用,个数一般和CPU核心相等,主要是为了提高性能,比较频繁的创建和销毁线程是比较重的行为。
那要例子中的操作应该怎么办呢?play引入了await方法和Promise对象 ,Promise继承了java 并发框架中的Future
这样写
Promise<String> delayedResult = veryLongComputation(…);
String result = await(delayedResult);
具体示例就是
await(new Job<Long>(){
@Override
public Long doJobWithResult() throws Exception {
synchronized(TestC.class){
Thread.sleep(10000);
}
return null;
}
}.now())
这样其实就开启了另外一个线程,本次请求被挂起但是线程并未阻塞,其它请求仍然可用
参考:https://www.playframework.com/documentation/1.3.x/asynchronous 的Continuations部分的内容