- 有时候会一条线程会分步骤进行,第二个步骤依赖于第一个步骤运行的结果。在多线程的情况下很容易出现线程安全的问题。这其中需要一个线程安全的中间上下问来帮助。
- 优化:借助ThreadLocal(有点像一个以线程为key值的map)来构建上下文。他相当于是每一个线程的自己的保险箱。
- Context 上下文具体类
public class Context {
private String name;
private String cardId;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public String getCardId() {
return cardId;
}
}
- ActionContext(关键,借助ThreadLocal,把Context放入,自己是单例的)
public final class ActionContext {
private static final ThreadLocal<Context> threadLocal = new ThreadLocal<Context>() {
@Override
protected Context initialValue() {
return new Context();
}
};
private static class ContextHolder {
private final static ActionContext actionContext = new ActionContext();
}
public static ActionContext getActionContext() {
return ContextHolder.actionContext;
}
public Context getContext() {
return threadLocal.get();
}
private ActionContext(){
}
}
- 模拟第一个步骤,从数据库获取数据,此时与context发生了交互
public class QueryFromDBAction {
public void execute() {
try {
Thread.sleep(1000L);
String name = "Alex " + Thread.currentThread().getName();
ActionContext.getActionContext().getContext().setName(name);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 第二个步骤依赖于第一个步骤,模拟从http获取数据
public class QueryFromHttpAction {
public void execute() {
Context context = ActionContext.getActionContext().getContext();
String name = context.getName();
String cardId = getCardId(name);
context.setCardId(cardId);
}
private String getCardId(String name) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "435467523543" + Thread.currentThread().getId();
}
}
- 线程真正运行的Runnable(有了上下文,即使是在执行后再创建上下文对象,无需交互,也能获取想要的数值)
public class ExecutionTask implements Runnable {
private QueryFromDBAction queryAction = new QueryFromDBAction();
private QueryFromHttpAction httpAction = new QueryFromHttpAction();
@Override
public void run() {
queryAction.execute();
System.out.println("The name query successful");
httpAction.execute();
System.out.println("The card id query successful");
Context context = ActionContext.getActionContext().getContext();
System.out.println("The Name is " + context.getName() + " and CardId " + context.getCardId());
}
}
public class ContextTest {
public static void main(String[] args) {
IntStream.range(1, 5)
.forEach(i ->
new Thread(new ExecutionTask()).start()
);
}
}
网友评论