Threadlocal的一二三四五

来源:互联网 发布:mysql 删除 索引 编辑:程序博客网 时间:2024/04/28 22:37

1.了结threadlocal。

Threadlocal是一个容器,用于存放线程的局部变量,它是为了解决多线程并发问题而设计的,不过设计有些难用,所以没有被广泛使用,其实它还是挺有用的。

ThreadLocal 的 API,其实很简单。
  1. public void set(T value):将值放入线程局部变量中
  2. public T get():从线程局部变量中获取值
  3. public void remove():从线程局部变量中移除值(有助于 JVM 垃圾回收)
  4. protected T initialValue():返回线程局部变量中的初始值(默认为 null)

可以自己写一个thread:

ublic class MyThreadLocal<T> {     private Map<Thread, T> container = Collections.synchronizedMap(new HashMap<Thread, T>());     public void set(T value) {        container.put(Thread.currentThread(), value);    }     public T get() {        Thread thread = Thread.currentThread();        T value = container.get(thread);        if (value == null && !container.containsKey(thread)) {            value = initialValue();            container.put(thread, value);        }        return value;    }     public void remove() {        container.remove(Thread.currentThread());    }     protected T initialValue() {        return null;    }}
以上实现了一个 ThreadLocal,其中中定义了一个同步 Map。

下面用这 MyThreadLocal 再来实现一把看看。

public class SequenceC implementsSequence {     privatestatic MyThreadLocal<Integer> numberContainer =new MyThreadLocal<Integer>() {        @Override        protectedInteger initialValue() {            return0;        }    };     publicint getNumber() {        numberContainer.set(numberContainer.get() +1);        returnnumberContainer.get();    }     publicstatic void main(String[] args) {        Sequence sequence =new SequenceC();         ClientThread thread1 =new ClientThread(sequence);        ClientThread thread2 =new ClientThread(sequence);        ClientThread thread3 =new ClientThread(sequence);         thread1.start();        thread2.start();        thread3.start();    }}


这就很好的起到了线程安全的作用,一个线程一个门一把钥匙。


2.threadlocal的应用

当修改产品价格的时候,需要记录操作日志,什么时候做了什么事情。

update product set price = ? where id = ?insert into log (created, description) values (?, ?)

DBUtil工具类

public class DBUtil {    // 数据库配置    private static final String driver = "com.mysql.jdbc.Driver";    private static final String url = "jdbc:mysql://localhost:3306/demo";    private static final String username = "root";    private static final String password = "root";     // 定义一个用于放置数据库连接的局部线程变量(使每个线程都拥有自己的连接)    private static ThreadLocal<Connection> connContainer = new ThreadLocal<Connection>();     // 获取连接    public static Connection getConnection() {        Connection conn = connContainer.get();        try {            if (conn == null) {                Class.forName(driver);                conn = DriverManager.getConnection(url, username, password);            }        } catch (Exception e) {            e.printStackTrace();        } finally {            connContainer.set(conn);        }        return conn;    }     // 关闭连接    public static void closeConnection() {        Connection conn = connContainer.get();        try {            if (conn != null) {                conn.close();            }        } catch (Exception e) {            e.printStackTrace();        } finally {            connContainer.remove();        }    }}

接口实现类:

public class ProductServiceImpl implements ProductService {     private static final String UPDATE_PRODUCT_SQL = "update product set price = ? where id = ?";    private static final String INSERT_LOG_SQL = "insert into log (created, description) values (?, ?)";     public void updateProductPrice(long productId, int price) {        try {            // 获取连接            Connection conn = DBUtil.getConnection();            conn.setAutoCommit(false); // 关闭自动提交事务(开启事务)             // 执行操作            updateProduct(conn, UPDATE_PRODUCT_SQL, productId, price); // 更新产品            insertLog(conn, INSERT_LOG_SQL, "Create product."); // 插入日志             // 提交事务            conn.commit();        } catch (Exception e) {            e.printStackTrace();        } finally {            // 关闭连接            DBUtil.closeConnection();        }    }     private void updateProduct(Connection conn, String updateProductSQL, long productId, int productPrice) throws Exception {        PreparedStatement pstmt = conn.prepareStatement(updateProductSQL);        pstmt.setInt(1, productPrice);        pstmt.setLong(2, productId);        int rows = pstmt.executeUpdate();        if (rows != 0) {            System.out.println("Update product success!");        }    }     private void insertLog(Connection conn, String insertLogSQL, String logDescription) throws Exception {        PreparedStatement pstmt = conn.prepareStatement(insertLogSQL);        pstmt.setString(1, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));        pstmt.setString(2, logDescription);        int rows = pstmt.executeUpdate();        if (rows != 0) {            System.out.println("Insert log success!");        }    }}












0 0