快速理解爲何要使用ThreadLocal?

問題場景一:高併發的時候,我們在調用一些公有的對象資源的時候,會有線程安全問題。

解決線程安全問題
方法一:對全局變量進行加鎖。缺點是其他線程要使用的話,就必須等待,耗時。
方法二:把全局變量變成局部方法變量。這樣就解決了線程安全問題。

問題場景二:我既要解決安全問題,我又要實現全局共享呢。

很多地方我們都需要這樣做。比如:我們需要獲取數據庫連接的時候,我們會單獨封裝一個方法叫getConnection()這個方法用來獲取connect
,那麼我們還會封裝幾個方法
commit()提交事物,
rollback()回滾事物的方法,
closeConnection()關閉連接方法。
這幾個方法自然需要共用一個connection對象才能對當前連接進行操作。

那麼如何共用呢?全局變量會造成線程安全問題,加鎖會對性能有影響,設置爲局部變量,那麼就不能在各個方法中使用了。 我們現在需要一個:既能夠共用,但又不是全局變量線程安全的東西,彷彿是局部定義的變量能夠在各個方法中重用一樣。

這個時候就可以使用ThreadLocal來解決既能夠共用,又不會造成線程安全的問題。**

至於ThreadLocal怎麼用,網上很多例子,我也看了,但是看來看去都沒說爲什麼要用,只說了怎麼用,怎麼用的博客太多了。我這裏就簡單的貼一下代碼案例:

package day02;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.commons.dbcp.BasicDataSource;

/**
 * 該類用於維護數據庫連接
 * @author tarena
 *
 */
public class DBUtil {
	/*
	 * ThreadLocal用於線程跨方法共享數據使用
	 
	 * TheaddLocal內部有一個Map,key爲要共
	 * 享數據的線程本身,value就是其需要共享的數據。
	 */
	private static ThreadLocal<Connection> tl;
	private static BasicDataSource dataSource;
	private static String className;
	private static String url;
	private static String username;
	private static String password;
	static{
		tl = new ThreadLocal<Connection>();
		/*
		 * properties文件
		 * properties文件常被用來做配置文件,
		 * 結構簡單。
		 */
		
		try{
			Properties pro = new Properties();
			pro.load(new FileInputStream("src/main/java/day02/config.properties"));
			className = pro.getProperty("classname");
			url = pro.getProperty("url");
			username = pro.getProperty("username");
			password = pro.getProperty("password");
			int maxActive = Integer.parseInt(pro.getProperty("maxactive"));
			long maxWait = Long.parseLong(pro.getProperty("maxwait"));

			//初始化連接池
			dataSource = new BasicDataSource();
			dataSource.setDriverClassName(className);
			dataSource.setUrl(url);
			dataSource.setUsername(username);
			dataSource.setPassword(password);
			
			//設置最大連接
			dataSource.setMaxActive(maxActive);
			//設置最大等待時間
			dataSource.setMaxWait(maxWait);
			
		}catch(Exception e){
			e.printStackTrace();
		}

	}
	/**
	 * 獲取數據庫連接
	 * @return
	 * @throws SQLException 
	 * @throws ClassNotFoundException 
	 */
	public static  Connection getConnection() throws SQLException, ClassNotFoundException{
			Connection connection = dataSource.getConnection();
//			Class.forName(className);
//			Connection connection = DriverManager.getConnection(url,username,password);
			tl.set(connection);
			return connection;
	}
	/**
	 * 關閉數據庫
	 * @param conn
	 */
	public static void closeConnection(){
		try{
			//關閉連接前,提交事務
			TransCommit();
			//如果是使用連接池獲得的連接,那麼調用該連接的close方法不會關閉連接,只是表示當前連接使用完畢,空閒。
			Connection connection = tl.get();
			//刪除當前線程所存放的連接
			tl.remove();
			if(connection != null){
				connection.close();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	/*
	 * 開啓事務
	 */
	public static void TransBegin(){
		
		try {
			tl.get().setAutoCommit(false);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	//回滾事務
	public static void TransRollBack(){
		try {
			tl.get().rollback();
			tl.get().setAutoCommit(true);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	//提交事務
	public static void TransCommit(){
		try {
			tl.get().commit();
			tl.get().setAutoCommit(true);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章