@Java并发编程之ThreadLocal详解
##ThreadLocal简介
变量值的共享可以使用public static的形式,所有线程都使用同一个变量,如果想实现每一个线程都有自己的共享变量该如何实现呢?JDK中的ThreadLocal类正是为了解决这样的问题。
ThreadLocal类并不是用来解决多线程环境下的共享变量问题,而是用来提供线程内部的共享变量,在多线程环境下,可以保证各个线程之间的变量互相隔离、相互独立。在线程中,可以通过get()/set()方法来访问变量。ThreadLocal实例通常来说都是private static类型的,它们希望将状态与线程进行关联。这种变量在线程的生命周期内起作用,可以减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
###测试类
@ContextConfiguration("classpath:applicationContext.xml")
public class Transfer {
@Autowired
private TransferService transferService;
@Test
public void test() throws Exception {
transferService.transfer("王二","王四",10f);
}
}
Service业务层
//转账
void transfer(String aName,String bName,Float balance);
}
```
package com.it.Service.impl;
import com.it.Dao.TransferDao;
import com.it.Domain.AcCount;
import com.it.Service.TransferService;
import com.it.Service.TxManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service //将此类进行实例化
public class TransferServiceImpl implements TransferService {
@Autowired //为属性进行依赖注入
private TransferDao transferDao;
@Autowired
private TxManager txManager;
public void transfer(String aName, String bName, Float balance) {
try {
//开启事务(关闭事务的自动提交)
txManager.begin();
//1.接收数据库返回的数据
AcCount byName1 = transferDao.findByName(aName);
AcCount byName2 = transferDao.findByName(bName);
//2.进行转账操作
byName1.setBalance(byName1.getBalance() - 10);
byName2.setBalance(byName2.getBalance() + 10);
//3.将数据更新到数据库中
transferDao.update(byName1);
int i = 1 / 0;
transferDao.update(byName2);
//事务提交
txManager.commit();
} catch (Exception e) {
e.printStackTrace();
//事务回滚
txManager.rollback();
} finally {
//关闭事务
txManager.close();
}
}
}
Dao持久层代码
这里采用的是DbUtils的工具类操作数据库
Dbutils是Apache的一款工具类,底层封装了jdbc的技术
public interface TransferDao {
//查询数据库balance金额
AcCount findByName(String name);
//将金额更新到数据库中
void update(AcCount acCount);
}
```
package com.it.Dao.impl;
import com.it.Dao.TransferDao;
import com.it.Domain.AcCount;
import com.it.Service.TxManager;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.sql.SQLException;
@Repository
public class TransferDaoImpl implements TransferDao {
@Autowired
private QueryRunner queryRunner;
@Autowired
private TxManager txManager;
public AcCount findByName(String name) {
try {
return queryRunner.query(txManager.getConnection(),"select * from account where name = ? ",
new BeanHandler<AcCount>(AcCount.class),name);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public void update(AcCount acCount) {
try {
queryRunner.update(txManager.getConnection(),"update account set balance = ? where name = ?",
acCount.getBalance(),acCount.getName());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
##TxManager工具类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
@Component
public class TxManager {
//使用ThreadLocal类储存connection对象
private ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
@Autowired //创建Druid连接池并依赖注入
private DataSource dataSource;
//获取到Connection
public Connection getConnection() throws SQLException {
//获取一个jdbc中的Connection接口
Connection connection = threadLocal.get();
if (connection == null){ //如果属性是空
connection = dataSource.getConnection(); //那么就获取一个Connection对象
threadLocal.set(connection); //将connection对象存储进本地集合中
}
return connection;
}
//开启事务
public void begin(){
try {
getConnection().setAutoCommit(false); //关闭自动提交事务
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交事务
public void commit(){
try {
getConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
//回滚事务
public void rollback(){
try {
getConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭事务
public void close(){
try {
getConnection().close();
threadLocal.remove(); //关闭事务之后,将Thread线程从集合中删除
} catch (SQLException e) {
e.printStackTrace();
}
}
}