Java ThreadLocal的使用案例

Posted 进无止境

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java ThreadLocal的使用案例相关的知识,希望对你有一定的参考价值。

本文以数据库操作Dao为例进行描述ThreadLocal的使用,如下是一个反例:

 

package com.daxin.threadlocal.dao;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class UserDaoErrorDemo {

	// ①一个非线程安全的变量
	private Connection conn;

	/**
	 * addUser在并发时候关于事务的提交容易出现错乱
	 */
	public void addUser() {
		try {

			// ②引用非线程安全变量
			conn.setAutoCommit(false);
			Statement stat = conn.createStatement();
			stat.executeQuery("sql");
			conn.commit();
		} catch (SQLException e) {
			e.printStackTrace();
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}
	}
}

 

上面存在线程安全问题,在多个线程进行事务提交时候会出现错乱。因此可以通过如下方案:

package com.daxin.threadlocal.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 模拟数据库连接管理器
 * 
 * @author liuguangxin
 *
 */
class ConnectionManager {

	static String driverName = "";
	static String url = "";
	static String user = "";
	static String password = "";

	public static Connection getConnection() {

		try {
			return DriverManager.getConnection(url, user, password);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

}
/**
 *
 * @author liuguangxin
 *
 */
public class UserDao {

	// ①使用ThreadLocal保存Connection变量
	//  由于Dao通产刚在系统中是单例的,因此可以被多个线程共享,因此connThreadLocal也是被多个线程共享的。
	private  ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();

	public Connection getConnection() {
		// ②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection, 并将其保存到线程本地变量中。
		if (connThreadLocal.get() == null) {
			Connection conn = ConnectionManager.getConnection();
			connThreadLocal.set(conn);
			return conn;
		} else {
			// ③直接返回线程本地变量
			return connThreadLocal.get();
		}
	}

	public void addUser(String userName, String passWord) {

		Connection conn = getConnection();
		Statement stmt = null;
		try {
			conn.setAutoCommit(false);
			stmt = conn.createStatement();
			// 伪代码
			stmt.executeQuery("insert into user ....");
			conn.commit();
		} catch (SQLException e) {
			e.printStackTrace();
			try {
				conn.rollback();
			} catch (SQLException ex) {
				ex.printStackTrace();
			}
		} finally {
			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

	}

}

  

 

以上是关于Java ThreadLocal的使用案例的主要内容,如果未能解决你的问题,请参考以下文章

Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例&源码分析

javaThreadLocal 内存泄漏 代码演示 实例演示

Java——聊聊JUC中的ThreadLocal

Java——聊聊JUC中的ThreadLocal

Java面试题必备知识之ThreadLocal

Java面试之ThreadLocal的使用