ThreadLocal的介紹與運用( 二 )


public class Demo02 {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}public static void main(String[] args) {Demo02 demo02 = new Demo02();for (int i = 0; i < 5; i++) {Thread t = new Thread(){@Overridepublic void run() {synchronized (Demo02.class){demo02.setContent(Thread.currentThread().getName() + "的數據");System.out.println("-------------------------------------");String content = demo02.getContent();System.out.println(Thread.currentThread().getName() + "--->" + content);}}};t.setName("線程" + i);t.start();}}}打印結果:
?

ThreadLocal的介紹與運用

文章插圖
? 從結果可以發現, 加鎖確實可以解決這個問題 , 但是在這里我們強調的是線程數據隔離的問題,并不是多線程共享數據的問題, 在這個案例中使用synchronized關鍵字是不合適的 。
1.3.2 ThreadLocal與synchronized的區別? 雖然ThreadLocal模式與synchronized關鍵字都用于處理多線程并發訪問變量的問題, 不過兩者處理問題的角度和思路不同 。
synchronizedThreadLocal原理同步機制采用'以時間換空間'的方式, 只提供了一份變量,讓不同的線程排隊訪問ThreadLocal采用'以空間換時間'的方式, 為每一個線程都提供了一份變量的副本,從而實現同時訪問而相不干擾側重點多個線程之間訪問資源的同步性多線程中讓每個線程之間的數據相互隔離總結: 在剛剛的案例中,雖然使用ThreadLocal和synchronized都能解決問題,但是使用ThreadLocal更為合適,因為這樣可以使程序擁有更高的并發性 。2. 運用場景_事務案例? 通過以上的介紹,我們已經基本了解ThreadLocal的特點 。但是它具體的應用是在哪里呢? 現在讓我們一起來看一個ThreadLocal的經典運用場景: 事務 。
2.1 轉賬案例2.1.1 場景構建? 這里我們先構建一個簡單的轉賬場景: 有一個數據表account , 里面有兩個用戶Jack和Rose,用戶Jack給用戶Rose 轉賬 。
? 案例的實現就簡單的用mysql數據庫,JDBC 和 C3P0 框架實現 。以下是詳細代碼 :
? (1) 項目結構
ThreadLocal的介紹與運用

文章插圖
? (2) 數據準備
-- 使用數據庫use test;-- 創建一張賬戶表create table account( id int primary key auto_increment, name varchar(20), money double);-- 初始化數據insert into account values(null, 'Jack', 1000);insert into account values(null, 'Rose', 1000);? (3) C3P0配置文件和工具類
<c3p0-config><!-- 使用默認的配置讀取連接池對象 --><default-config> <!--連接參數 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property> <property name="user">root</property> <property name="password">1234</property> <!-- 連接池參數 --> <property name="initialPoolSize">5</property> <property name="maxPoolSize">10</property> <property name="checkoutTimeout">3000</property></default-config></c3p0-config>?(4) 工具類 : JdbcUtils
package com.itheima.transfer.utils;import com.mchange.v2.c3p0.ComboPooledDataSource;import java.sql.Connection;import java.sql.SQLException;public class JdbcUtils {// c3p0 數據庫連接池對象屬性private static final ComboPooledDataSource ds = new ComboPooledDataSource();// 獲取連接public static Connection getConnection() throws SQLException {return ds.getConnection();}//釋放資源public static void release(AutoCloseable... ios){for (AutoCloseable io : ios) {if(io != null){try {io.close();} catch (Exception e) {e.printStackTrace();}}}}public static void commitAndClose(Connection conn) {try {if(conn != null){//提交事務conn.commit();//釋放連接conn.close();}} catch (SQLException e) {e.printStackTrace();}}public static void rollbackAndClose(Connection conn) {try {if(conn != null){//回滾事務conn.rollback();//釋放連接conn.close();}} catch (SQLException e) {e.printStackTrace();}}}? (5) dao層代碼 : AccountDao
package com.itheima.transfer.dao;import com.itheima.transfer.utils.JdbcUtils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;public class AccountDao {public void out(String outUser, int money) throws SQLException {String sql = "update account set money = money - ? where name = ?";Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,outUser);pstm.executeUpdate();JdbcUtils.release(pstm,conn);}public void in(String inUser, int money) throws SQLException {String sql = "update account set money = money + ? where name = ?";Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,inUser);pstm.executeUpdate();JdbcUtils.release(pstm,conn);}}

推薦閱讀