上下文模式(Threadlocal实现)
在web中碰到运行上下文内容,可以用threadlocal的原理来实现,通过这种方式,更能明白网络请求中的上下文是如何实现的
使用场景:网络请求的数据分别在DB和其他http中,通过threadlocal隔离其他线程的访问本线程的内容,达到多线程安全的目的
上下文内容属性
package com.ln.concurrent.chapter11;
/**
* @ProjectName: java-concurrency
* @Package: com.ln.concurrent.chapter11
* @Name:Context
* @Author:linianest
* @CreateTime:2020/3/29 19:15
* @version:1.0
* @Description TODO: 定义上下文
*/
/**
* context封装的属性
*/
public class Context {
private String name;
private String cardId;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public String getCardId() {
return cardId;
}
}
请求从DB中获取数据
package com.ln.concurrent.chapter11;
/**
* @ProjectName: java-concurrency
* @Package: com.ln.concurrent.chapter11
* @Name:QueryAction
* @Author:linianest
* @CreateTime:2020/3/29 19:13
* @version:1.0
* @Description TODO: 请求从DB中获取数据
*/
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();
}
}
}
从网络获取数据
package com.ln.concurrent.chapter11;
/**
* @ProjectName: java-concurrency
* @Package: com.ln.concurrent.chapter11
* @Name:QueryFromHttpAction
* @Author:linianest
* @CreateTime:2020/3/29 19:23
* @version:1.0
* @Description TODO: 从网络获取数据
*/
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 "123435344354" + Thread.currentThread().getId();
}
}
将上下文内容与ThreadLocal绑定
package com.ln.concurrent.chapter11;
/**
* @ProjectName: java-concurrency
* @Package: com.ln.concurrent.chapter11
* @Name:ActionContext
* @Author:linianest
* @CreateTime:2020/3/30 9:18
* @version:1.0
* @Description TODO: 将上下文内容与ThreadLocal绑定
*/
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();
}
}
请求任务执行线程
package com.ln.concurrent.chapter11;
/**
* @ProjectName: java-concurrency
* @Package: com.ln.concurrent.chapter11
* @Name:ExecutionTask
* @Author:linianest
* @CreateTime:2020/3/29 19:12
* @version:1.0
* @Description TODO: 请求任务执行线程
*/
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());
}
}
客户端测试上下文请求任务
package com.ln.concurrent.chapter11;
import java.util.stream.IntStream;
/**
* @ProjectName: java-concurrency
* @Package: com.ln.concurrent.chapter11
* @Name:ContextTest
* @Author:linianest
* @CreateTime:2020/3/29 19:45
* @version:1.0
* @Description TODO: 测试上下文请求任务
*/
public class ContextTest {
public static void main(String[] args) {
IntStream.range(1, 5)
.forEach(i -> {
new Thread(new ExecutionTask()).start();
});
}
}
通过以上的方式,实现了线程的隔离,不用担心线程安全的问题,但是如果是线程池调用,一定要在下一次请求前,情况本地线程的缓存