深入解析ThreadLocal( 二 )

打印结果:
从结果可以看出多个线程在访问同一个变量的时候出现的异常 , 线程间的数据没有隔离 。 下面我们来看下采用 ThreadLocal 的方式来解决这个问题的例子 。
public class MyDemo {?private static ThreadLocal tl = new ThreadLocal<>();?private String content;?private String getContent() {return tl.get();}?private void setContent(String content) {tl.set(content);}?public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}}打印结果:
从结果来看 , 这样很好的解决了多线程之间数据隔离的问题 , 十分方便 。
1.3 ThreadLocal类与synchronized关键字1.3.1 synchronized同步方式这里可能有的朋友会觉得在上述例子中我们完全可以通过加锁来实现这个功能 。 我们首先来看一下用synchronized代码块实现的效果:
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();}}}打印结果:
从结果可以发现, 加锁确实可以解决这个问题 , 但是在这里我们强调的是线程数据隔离的问题 , 并不是多线程共享数据的问题, 在这个案例中使用synchronized关键字是不合适的 。
1.3.2 ThreadLocal与synchronized的区别虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题, 不过两者处理问题的角度和思路不同 。
synchronizedThreadLocal
总结: 在刚刚的案例中 , 虽然使用ThreadLocal和synchronized都能解决问题,但是使用ThreadLocal更为合适,因为这样可以使程序拥有更高的并发性 。 2. 运用场景_事务案例通过以上的介绍 , 我们已经基本了解ThreadLocal的特点 。 但是它具体是运用在什么场景中呢? 接下来让我们看一个案例: 事务操作 。
2.1 转账案例2.1.1 场景构建这里我们先构建一个简单的转账场景: 有一个数据表account , 里面有两个用户Jack和Rose , 用户Jack 给用户Rose 转账 。
案例的实现主要用mysql数据库 , JDBC 和 C3P0 框架 。 以下是详细代码 :
(1) 项目结构
(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', 0);(3) C3P0配置文件和工具类
com.mysql.jdbc.Driverjdbc:mysql://localhost:3306/testroot