zoukankan      html  css  js  c++  java
  • ThreadLocal

    ThreaedLocal本质上是一个存数据的map集合,元素的键默认为当前线程,值是通过set()方法存储的数据。

    1、向线程中取数据和存放数据:

    package pers.zhb.thread;
    import java.util.Random;
    public class ThreadDemo {
        private static ThreadLocal<Integer> x=new ThreadLocal<Integer>();
        public static void main(String[] args){
            for(int i=0;i<2;i++){//创建线程
                new Thread(new Runnable(){
                    public void run(){
                        int data=new Random().nextInt();//随机数
                        System.out.println(Thread.currentThread().getName()+"data"+data);
                        x.set(data);//数据放入线程
                        new A().get();
                        new B().get();
                    }
                }).start();
            }
        }
        static class A{
            public void get(){
                int data=x.get();
                System.out.println("A"+Thread.currentThread().getName()+"data"+data);
            }
        }
        static class B {
            public void get() {
                int data =x.get();
                System.out.println("B" + Thread.currentThread().getName() + "data" + data);
            }
        }
    }

    运行结果:

     开辟的两个线程,分别存放不同的数据,但是在取出数据的时候用两个类中的方法去取数据,数据的值是相同的。也就是说同一个线程中的数据是可以共享的。

    2、ThreadLocal的应用:

    在使用事务进行银行转账的项目中(https://www.cnblogs.com/zhai1997/p/11703092.html),虽然实现了转账的功能,但是为了保证对事务的处理操纵的始终是同一个对象,Connection对象的创建写在了Service层,并可以向dao层传递该参数,把Connection对象的创建写在Service层是不合理的。因此,可以创建一个数据库工具类将对Connection对象的创建引入到工具类里面,dao层和Service层的Connection对象的获取都是通过工具类里里面的方法获得的。

    而工具类里面的Connection对象是从ThreadLocal中获得的,如果ThreadLocal为空,则重新从连接池中获取Connection对象,即通过ThreadLocal的数据共享功能实现了Connection对象的一致。

    代码实现:

    jsp:

    <form action="${pageContext.request.contextPath}/transferservlet" method="post">
        转出账户:<input type="text" name="out"><br>
        转入账户:<input type="text" name="in"><br>
        转账金额:<input type="text" name="money"><br>
        <input type="submit" value="确认转账"><br>
    </form>

    web层:

    Servlet:

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
            response.setContentType("text/html;charset=utf-8");
            String inName=request.getParameter("in");//从表单获得的数据都为字符串类型
            String outName=request.getParameter("out");
            String stringmoney=request.getParameter("money");
            double money=Double.parseDouble(stringmoney);//字符串类型的money变为double
            TransferService transferService=new TransferService();
            boolean result=transferService.transfer(outName,inName,money);
            if(result){
                response.getWriter().write("成功");
            }else{
                response.getWriter().write("失败");
            }
        }

    从表单获得数据。

    Service层:

     public boolean transfer(String outName,String inName,double money) {
            boolean result=true;
            try {
                ThreaddbUtils.startTransaction();//将Connection对象隐藏在了ThreaddbUtils中
                TransferDao dao = new TransferDao();
                dao.out(outName, money);//将同一个con对象以参数的形式传递到dao层
                //int num=8/0;//故意制造异常,使得转账过程意外终止
                dao.in(inName, money);
            }catch (Exception e){
                result=false;
                try {
                        ThreaddbUtils.rollback();//调用工具类里面的rollback()方法
                }catch (Exception e1){
                    e1.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                ThreaddbUtils.commit();//调用工具类里面的commit()方法
            }
            return true;
        }

    对转账事务进行处理,无异常则直接提交,有异常则回滚。

    dao层:

    public class TransferDao {
        public void out(String outName, double money) {
            try {
                Connection con= ThreaddbUtils.getConnection();
                QueryRunner qr = new QueryRunner();
                String sql = "UPDATE transfer SET money=money-? WHERE username=? ";
                Object[] update = {money, outName};
                qr.update(con, sql, update);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        public void in(String inName, double money) {
            try {
                Connection con= ThreaddbUtils.getConnection();
                QueryRunner qr = new QueryRunner();
                String sql = "UPDATE transfer SET money=money+? WHERE username=? ";
                Object[] update = {money, inName};
                qr.update(con, sql, update);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    从工具类里面的ThreadLocal方法中获得Connection对象,保证操作的是同一个Connection对象。

    工具类:

    public class ThreaddbUtils {
        private static ComboPooledDataSource dataSource = new ComboPooledDataSource("zhai");
        private static ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();//只存储元素的值,键已经默认了
        public static void startTransaction(){
            Connection con=getConnection();
            try{
                con.setAutoCommit(false);
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        public static Connection getConnection() {
            try {
                Connection con=threadLocal.get();//先尝试从集合中获取Connection的对象
                if(con==null){//Map集合中没有connection对象,则从连接池中获取一个,并将该对象存储到map集合中
                 con= dataSource.getConnection();
                 threadLocal.set(con);//存储Connection对象
                }
                return con;
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        public static void rollback(){
            try{
                getConnection().rollback();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        public static void commit(){
            try{
    Connection con=getConnection();
    con.commit();
    threadLocal.remove();
    con.close();
    }catch (SQLException e){ e.printStackTrace(); } } }

    将Connection对象存放在ThreadLocal对象中,只要是调用getConnection()方法获得的连接都是同一个Connection对象,并将回滚和提交写在此工具类内部,保证了Service层不会再出现创建Connection对象的现象。

  • 相关阅读:
    js项目练习第二课
    js项目练习第一课
    进度条
    js基础
    反射
    递归函数与三级菜单
    mybatis 动态SQL
    java 面对对象(抽象 继承 接口 多态)
    java Eclipse debug技巧
    mybatis 调用存储过程
  • 原文地址:https://www.cnblogs.com/zhai1997/p/11708943.html
Copyright © 2011-2022 走看看