zoukankan      html  css  js  c++  java
  • ThreadLocal的应用场景

    场景一:用来替代参数链传递
    每个线程内需要保存类似于全局变量的信息(例如在拦截器中获取的用户信息),可以让不同方法直接使用,避免参数传递的麻烦却不想被多线程共享(因为不同线程获取到的用户信息不一样)。
    例如,用 ThreadLocal 保存一些业务内容(用户权限信息、从用户系统获取到的用户名、用户ID 等),这些信息在同一个线程内相同,但是不同的线程使用的业务内容是不相同的。
    在线程生命周期内,都通过这个静态 ThreadLocal 实例的 get() 方法取得自己 set 过的那个对象,避免了将这个对象(如 user 对象)作为参数传递的麻烦。
    比如说我们是一个用户系统,那么当一个请求进来的时候,一个线程会负责执行这个请求,然后这个请求就会依次调用service-1()、service-2()、service-3()、service-4(),这4个方法可能是分布在不同的类中的。

    场景二:这种场景通常用于保存线程不安全的工具类,典型的需要使用的类就是 SimpleDateFormat
    参考:https://www.cnblogs.com/zz-ksw/p/12684877.html

    场景三:数据库连接
    1.jdbc连接数据库,就这样子

    Class.forName("com.mysql.jdbc.Driver");
    java.sql.Connection conn = DriverManager.getConnection(jdbcUrl);
    

    2.通过传入jdbc url用Drivermanager.getConnection(jdbcurl)连接数据库,

    注意:一次Drivermanager.getConnection(jdbcurl)获得只是一个connection,并不能满足高并发情况。因为connection不是线程安全的,一个connection对应的是一个事物。

    3.所以数据库连接池,是多次Drivermanager.getConnection(jdbcurl),获取多个connection放入hashmap中。

    4.每次获得connection都需要浪费cpu资源和内存资源,是很浪费资源的。所以诞生了数据库连接池。

    5.数据库连接池部分源码:

    注意pool.getConnection(),都是先从threadlocal里面拿的,如果threadlocal里面有,则用,保证线程里的多个dao操作,用的是同一个connection,以保证事务。

    如果新线程,则将新的connection放在threadlocal里,再get给到线程。

    着重看以下几个方法,说明数据库连接池,是将connection放进threadlocal里的,以保证每个线程从连接池中获得的都是线程自己的connection。

     // 将线程和连接绑定,保证事务能统一执行  
     成员变量   private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(); 
     // 获得当前连接  
        public Connection getCurrentConnecton(){  
            // 默认线程里面取  
            Connection conn = threadLocal.get();  
            if(!isValid(conn)){  
                conn = getConnection();  
            }  
            return conn;  
        }  
    
    // 获得连接  
        public synchronized Connection getConnection() {  
            Connection conn = null;  
            try {  
                // 判断是否超过最大连接数限制  
                if(contActive < this.dbBean.getMaxActiveConnections()){  
                    if (freeConnection.size() > 0) {  
                        conn = freeConnection.get(0);  
                        if (conn != null) {  
                            threadLocal.set(conn);  
                        }  
                        freeConnection.remove(0);  
                    } else {  
                        conn = newConnection();  
                    }  
                      
                }else{  
                    // 继续获得连接,直到从新获得连接  
                    wait(this.dbBean.getConnTimeOut());  
                    conn = getConnection();  
                }  
                if (isValid(conn)) {  
                    activeConnection.add(conn);  
                    contActive ++;  
                }  
            } catch (SQLException e) {  
                e.printStackTrace();  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            return conn;  
        }
    public synchronized void releaseConn(Connection conn) throws SQLException {  
            if (isValid(conn)&& !(freeConnection.size() > dbBean.getMaxConnections())) {  
                freeConnection.add(conn);  
                activeConnection.remove(conn);  
                contActive --;  
                threadLocal.remove();  
                // 唤醒所有正待等待的线程,去抢连接  
                notifyAll();  
            }  
        } 
    
    首先,LZ是概念上的错误.什么是线程池,什么是ThreadLocal???
       线程池,为避免不必要的创建,销毁connection而存在的,其中包括活动,等待,最小等属性,cop3,proxy连接池都可以配置这些玩意;
       
       至于为什么要用ThreadLocal呢?这个和连接池无关,我认为更多的是和程序本身相关,为了更清楚的说明,我举个例子
       servlet中获取一个连接.首先,servlet是线程安全的吗?
         class MyServlet extends HttpServlet{
             private Connection conn;
         }
         ok,遗憾的告诉你,这个conn并不是安全的,所有请求这个servlet的连接,使用的都是一个Connection,这个就是致命的了.多个人使用同一个连接,算上延迟啥的,天知道数据会成什么样.
         因此我们要保证Connection对每个请求都是唯一的.这个时候就可以用到ThreadLocal了,保证每个线程都有自己的连接.
         改为 private ThreadLocal<Connection> ct = new ThreadLocal<Connnection>();
         然后从连接池获取Connection,set到ct中,再get就行了,至于得到的是哪个Connection就是连接池的问题了,你也管不到.
    

    Hibernate的数据库连接池就是将connection放进threadlocal实现的!!!

    参考:https://www.cnblogs.com/panxuejun/p/5920845.html

  • 相关阅读:
    对于java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I错误解决
    attempted to assign id from null one-to-one
    The class has no identifier property
    javax.servlet.ServletException: com.microsoft.jdbc.base.BaseDatabaseMetaData.supportsGetGeneratedKeys()Z
    final和static
    hibernate事务
    log4j:WARN Please initialize the log4j system properly.解决
    用最有效率的方法算出2乘以8等於几
    char型变量中能存贮一个中文汉字
    基本数据类型范围
  • 原文地址:https://www.cnblogs.com/six-hc/p/14194907.html
Copyright © 2011-2022 走看看