多线程设计模式-Servlet上下文模式(Threadlocal实现)

上下文模式(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();
                });
    }
}

通过以上的方式,实现了线程的隔离,不用担心线程安全的问题,但是如果是线程池调用,一定要在下一次请求前,情况本地线程的缓存

上一篇:2021年线上线下融合会议需求增长,Hilton EventReady Hybrid Solutions将启动


下一篇:FDTD Solutions安装过程缺少.net的问题解决解决方法