(8)Java多线程之ThreadLocal

  • 引言
  • ThreadLocal的使用
    • 1 ThreadLocal最简单的使用
    • 2 ThreadLocal实现的原理
    • 3 ThreadLocal在多线程中的使用
    • 4 使用ThreadLocal控制事务

1.引言

      在前面几篇博客中主要是介绍了多个线程之间交互,如果在多线程中操作同一个变量,那么如果想要实现每一个线程都有着自己的变量,那么应该如何实现呢?JDK为我们提供一个类ThreadLocal,使用ThreadLocal类我们实现线程内部变量。我们可以将ThreadLocal类比喻成存放数据的盒子(内部是以map对象实现),盒子里面存放每一个线程的私有数据

2.ThreadLocal的使用

2.1 ThreadLocal最简单的使用

import java.util.ArrayList;
import java.util.List;

public class app {
    static private ThreadLocal local=new ThreadLocal();
    public static void main(String[] args) {

        if(local.get()==null){
            System.out.println("");
            local.set("main线程中存在的值");
        }
        System.out.println(local.get());
    }

}

2.2 ThreadLocal实现的原理

我们前面说了,ThreadLocal类的底层是用map实现的,并且和当前线程想绑定,我们查看一下ThreadLocal底层原理的实现

  • get()方法

(8)Java多线程之ThreadLocal_第1张图片

  • set()方法

(8)Java多线程之ThreadLocal_第2张图片

  • 分析

      通过观察源码来看,我们首先获得当前线程的对象,然后将数据和当前线程对象绑定。并且底层是用map实现的。

2.3 ThreadLocal在多线程中的使用

  • 定义两个线程,在线程A中存放数据A,在线程B中存放数据B,在线程A中只能取得线程A储存的数据,在线程B中只能取得线程B中存储的数据。

  • 代码实例(线程A)


public class ThreadA extends Thread{
    private ThreadLocal local;
    public ThreadA(ThreadLocal local) {
        this.local=local;
    }
    public void run() {
        local.set("A");
        //注意我这里只是调用了get方法,并没有指定get的key(底层是map)
        System.out.println("线程A中的数值:"+local.get());

    }

}
  • 代码实例(线程B)
public class ThreadB extends Thread{
    private ThreadLocal local;
    public ThreadB(ThreadLocal local) {
        this.local=local;
    }
    public void run() {
        local.set("B");
        //注意我这里只是调用了get方法,并没有指定get的key(底层是map)
        System.out.println("线程B中的数值:"+local.get());

    }

}
  • main方法
import java.util.ArrayList;
import java.util.List;

public class app {
    static private ThreadLocal local=new ThreadLocal();
    public static void main(String[] args) {
        ThreadA a=new ThreadA(local);
        ThreadB b=new ThreadB(local);
        a.start();
        b.start();
    }

}
  • 运行结果(没问题)

(8)Java多线程之ThreadLocal_第3张图片

2.4 使用ThreadLocal控制事务

      在JavaWeb开发中,操作数据库的时候我们要开启事务,操作数据库是数据层(Dao)层的操作,而事物是业务层(Service)的操作,这个时候我们就可以利用ThreadLocal类控制层和层之间的事物。

  • 我们的事务工具类
import java.sql.Connection;
import java.sql.SQLException;


public class ConnectionManager {
    //创建一个私有静态的并且是与事务相关联的局部线程变量  
    private static ThreadLocal connectionHolder = new ThreadLocal();
    //获得数据库连接
    public static Connection getConnection(){  
        //获得线程变量connectionHolder的值conn  
        Connection conn = connectionHolder.get();  
        if (conn == null){  
                //使用DbUtil获得数据库连接 
                conn = DbUtil.getConnection();  
                //将局部变量connectionHolder的值设置为conn  
                connectionHolder.set(conn);  
        }     
        return conn;  
    }  
    /** 
     * 关闭连接和从线程变量中删除conn 
     */  
    public static void closeConnection(){  
        //获得线程变量connectionHolder的值conn  
        Connection conn = connectionHolder.get();  
        if (conn != null){  
            try {  
                //关闭连接  
                conn.close();  
                //从线程局部变量中移除conn,如果没有移除掉,下次还会用这个已经关闭的连接,就会出错  
                connectionHolder.remove();  
            }catch(SQLException e){  
                e.printStackTrace();  
            }  
        }  
    }
    /** 
     *开启事务,手动开启 
     */  
    public static void beginTransaction(Connection conn){  
            try {  
                //如果连接存在,再设置连接,否则会出错  
                if (conn != null){  
                        //默认conn是自动提交,  
                        if (conn.getAutoCommit()){  
                            //关闭自动提交,即是手动开启事务  
                            conn.setAutoCommit(false);  
                        }  
                    }  
            }catch(SQLException e){  
                e.printStackTrace();  
            }  
    } 
    /** 
     * 提交事务 
     */  
    public static void commitTransaction(Connection conn){  
        try{  
            if (conn != null){  
                if (!conn.getAutoCommit()){  
                    conn.commit();  
                }  
            }  
        }catch(SQLException e){  
            e.printStackTrace();  
        }  
    }
    /** 
     * 回滚事务 
     */  
    public static void rollbackTransaction(Connection conn){  
        try {  
            if (conn != null){  
                if(!conn.getAutoCommit()){  
                    conn.rollback();  
                }  
            }     
        }catch(SQLException e){  
            e.printStackTrace();  
        }     
    }  
}
  • 在Service类中如何调用
public void addUser(User user)
    {
        Connection conn = null;  
        try {  
            //从ThreadLocal中取得Connection  
            conn = ConnectionManager.getConnection();  
            //手动控制事务提交  
            ConnectionManager.beginTransaction(conn);               
            //添加用户
            userdao.addUser(user);            
            if (!conn.getAutoCommit()) {  
                //提交事务  
                ConnectionManager.commitTransaction(conn);  
            }  
        }catch(Exception e) {  
            e.printStackTrace();  
            if (!conn.getAutoCommit()) {  
                //回滚事务  
                ConnectionManager.rollbackTransaction(conn);  
            }  
        }finally {  
            ConnectionManager.closeConnection();  
        }

    }

你可能感兴趣的:(Java基础)