• 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();
    				}
    			}
    		}
    
    	}
    
    }
    

      

  • 相关阅读:
    verdi issues on license
    geci
    组合数据类型练习
    熟悉常用的Linux操作
    1.大数据概述
    c语言文法分析
    词法分析器#include<stdio.h> #include<string.h> #include<iostream.h> char prog[80],token[8]; char ch; int syn,p,m=0,n,row,sum=0; char *rwtab[6]={"begin","if","then","while","do","end"
    关于编译原理
    可变参数
    函数和指针
  • 原文地址:https://www.cnblogs.com/leodaxin/p/8656304.html
Copyright © 2020-2023  润新知