一、基本用法

  ThreadLocal是一个容器,用于存放线程的局部变量。如果ThreadLocalVariable(线程局部变量)更加好理解。

  在Jdk 1.2 java.lang.ThreadLocal开始使用,他是为解决多线程并发设计的.

  示例序列号生成,保证每个线程生成唯一序列号

编写Sequence接口

package com.lhx.chapter4.threadlocaltest;

public interface Sequence {
int getNumber();
}

编写线程类

package com.lhx.chapter4.threadlocaltest;

public class ClientThread extends Thread {
private Sequence sequence; public ClientThread(Sequence sequence){
this.sequence=sequence;
} @Override
public void run() {
for(int i=0;i<3;i++){
System.out.println(Thread.currentThread().getName()+"=>"+sequence.getNumber());
}
}
}

实现方式一

package com.lhx.chapter4.threadlocaltest;

public class SequenceA implements Sequence {
private static int number = 0;
@Override
public int getNumber() {
number=number+1;
return number;
} public static void main(String[] args) {
Sequence sequence = new SequenceA();
ClientThread clientThread1 = new ClientThread(sequence);
ClientThread clientThread2 = new ClientThread(sequence);
ClientThread clientThread3 = new ClientThread(sequence); clientThread1.start();
clientThread2.start();
clientThread3.start();
}
}
Thread-0=>1
Thread-1=>2
Thread-0=>3
Thread-1=>4
Thread-0=>5
Thread-1=>6
Thread-2=>7
Thread-2=>8
Thread-2=>9

由输出可以线程间共享一个Static变量,无法保证线程安全。

示例2,

package com.lhx.chapter4.threadlocaltest;

public class SequenceB implements Sequence {
private static ThreadLocal<Integer> numberContainer = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
@Override
public int getNumber() {
numberContainer.set(numberContainer.get()+1);
return numberContainer.get();
} public static void main(String[] args) {
Sequence sequence = new SequenceB();
ClientThread clientThread1 = new ClientThread(sequence);
ClientThread clientThread2 = new ClientThread(sequence);
ClientThread clientThread3 = new ClientThread(sequence); clientThread1.start();
clientThread2.start();
clientThread3.start();
}
}

输出值:

Thread-0=>1
Thread-0=>2
Thread-0=>3
Thread-1=>1
Thread-1=>2
Thread-1=>3
Thread-2=>1
Thread-2=>2
Thread-2=>3

可以看出每个线程变量独立开来,也就是说ThreadLocal为每个线程提供了一个副本。

ThreadLocal的API,

 public void set(T value)将值放入线程局部变量中

public T get() 从线程局部变量中获取值
public void remove()从线程局部变量中移除
protected T initialValue()返回线程局部变量的初始值(默认为null),必须默认实现。

自定义实现ThreadLocal

package com.lhx.chapter4.threadlocaltest;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map; public 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存放Jdbc Connection,以达到事务控制能力。

  示例,修改价格,记录日志

  update product set price=? where id=?

  insert into log(crerated,description)values(?,?)

编写工具类DBUtil  

package com.lhx.test.dbutil1;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; 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 Connection conn = null; public static Connection getConnection() {
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
} public static void colseConnection() {
try {
if(conn!=null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

编写ProductService

package com.lhx.test.dbutil1;

public interface ProductService {
void updateProductPrice(long productId,int price);
}

编写ProductService实现类编写ProductServiceImpl

package com.lhx.test.dbutil1;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.Date; 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(crerated,description)values(?,?)"; @Override
public void updateProductPrice(long productId, int price) {
try {
Connection connection = DBUtil.getConnection();
connection.setAutoCommit(false);
updateProduct(connection,Update_Product_sql,productId,price);
insertLog(connection,Update_Product_sql,"Create Product");
connection.commit();
} catch (Exception e) {
e.printStackTrace();
}finally {
DBUtil.colseConnection();
}
}
private void updateProduct(Connection connection,String sql,long productId,int price) throws Exception{
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setInt(1,price);
pstmt.setLong(2,productId);
int rows = pstmt.executeUpdate();
if(rows!=0){
System.out.println("update product success");
}
}
private void insertLog(Connection connection,String sql,String msg) throws Exception{
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1,new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss").format(new Date()));
pstmt.setString(2,msg);
int rows = pstmt.executeUpdate();
if(rows!=0){
System.out.println("insert log success");
}
}
}

个人测试

public static void main(String[] args) {
ProductService productService = new ProductServiceImpl();
productService.updateProductPrice(1,3000);
}

并发测试

package com.lhx.test.dbutil1;

import com.lhx.test.dbutil1.ProductService;

public class ClientThread extends Thread {
private ProductService productService; public ClientThread(ProductService productService) {
this.productService = productService;
} @Override
public void run() {
System.out.println(Thread.currentThread().getName());
productService.updateProductPrice(1, 3000);
}
}
    public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
ProductService productService = new ProductServiceImpl();
ClientThread clientThread = new ClientThread(productService);
clientThread.start();
}
}

使用ThreadLocal编写工具类

package com.lhx.test.dbutil2;

import java.sql.Connection;
import java.sql.DriverManager; 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> conContainer = new ThreadLocal<>(); public static Connection getConnection() {
Connection conn = conContainer.get();
try {
if (conn == null) {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
conContainer.set(conn);
}
return conn;
} public static void colseConnection() {
Connection conn = conContainer.get();
try {
if (conn != null) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
conContainer.remove();
}
}
}

008-ThreadLocal的更多相关文章

  1. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

  2. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  3. Threadlocal使用Case

    Threadlocal能够为每个线程分配一份单独的副本,使的线程与线程之间能够独立的访问各自副本.Threadlocal 内部维护一个Map,key为线程的名字,value为对应操作的副本. /** ...

  4. 多线程映射工具——ThreadLocal

    ThreadLocal相当于一个Map<Thread, T>,各线程使用自己的线程对象Thread.currentThread()作为键存取数据,但ThreadLocal实际上是一个包装了 ...

  5. ThreadLocal 工作原理、部分源码分析

    1.大概去哪里看 ThreadLocal 其根本实现方法,是在Thread里面,有一个ThreadLocal.ThreadLocalMap属性 ThreadLocal.ThreadLocalMap t ...

  6. ThreadLocal<T>的是否有设计问题

    一.吐槽 ThreadLocal<T>明显是.NET从JAVA中来的一个概念,但是这种设计是否出现了问题. 很明显,在JAVA中threadLocal直接是Thread的成员,当然随着th ...

  7. 理解ThreadLocal —— 一个map的key

    作用: 当工作于多线程中的对象使用ThreadLocal维护变量时,threadLocal为每个使用该变量的线程分配一个独立的变量副本. 接口方法: protected T initialValue( ...

  8. JavaSe:ThreadLocal

    JDK中有一个ThreadLocal类,使用很方便,但是却很容易出现问题.究其原因, 就是对ThreadLocal理解不到位.最近项目中,出现了内存泄漏的问题.其中就有同事在使用ThreadLocal ...

  9. 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal

    什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...

  10. ThreadLocal 源码剖析

    ThreadLocal是Java语言提供的用于支持线程局部变量的类.所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量(每个线程一个拷贝).在各个Java web的各种框架 ...

随机推荐

  1. GoogLeNet模型的微调

    我从零开始训练了GoogLeNet模型. 但它没有给我带来希望的结果. 作为替代,我想对我的数据集中的GoogLeNet模型进行微调. 有谁知道我应该遵循什么步骤? 采纳答案: 假设你正在尝试做图像分 ...

  2. putty英文乱码---DM8168_ETV_V1.1(路视明)

    配置參照http://jingyan.baidu.com/article/c74d600048ed620f6a595d12.html 注意事项: 假设出现 英文也乱码.那么就是波特率设置的问题,应该这 ...

  3. 串行 RapidIO

    https://wenku.baidu.com/view/78666616cf84b9d528ea7ad9.html

  4. AndroidManifest.xml配置

    AndroidManifest.xml配置文件对于Android应用开发来说是非常重要的基础知识,本文旨在总结该配置文件中重点的用法,以便日后查阅.下面是一个标准的AndroidManifest.xm ...

  5. 内核交互--debugfs_转

    转载:Linux内核里的DebugFS DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据.类似的虚拟文件系统还有procfs和sysfs等,这 ...

  6. 随机生成数,摘自算法竞赛入门经典P120-P123测试STL。

    //#include<bits/stdc++.h> #include<cstring> #include<iostream> #include<cstdio& ...

  7. Vsphere笔记07 Vcenter 部署流程 2

    7.Vcenter 部署流程 2   Vcenter 安装需求   1.硬件要求 CPU:支持VT-X技术并开启内存:4G或4G 以上   2.系统要求 Windows 2008 R2 x64 Vsp ...

  8. 【转】Monkey测试3——Monkey测试结果分析

    Monkey测试结果分析 一. 初步分析方法: Monkey测试出现错误后,一般的差错步骤为以下几步: 1. 找到是monkey里面的哪个地方出错 2. 查看Monkey里面出错前的一些事件动作,并手 ...

  9. [已解决]pycharm报错:AttributeError: module 'pip' has no attribute 'main'

    > 更新pip后,pycharm更新模块报错,经过一番查找,现提供两种解决办法. 报错片段信息如下: AttributeError: module 'pip' has no attribute ...

  10. ASP.NET动态网站制作(24)-- ADO.NET(3)

    前言:ADO.NET的第三节课.今天主要讲SQL Helper. 内容: 1.DataReader和DataSet的区别: (1)DataReader是一行一行地读,且只能向前读:DataSet是一次 ...