博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ThreadLocal 简介
阅读量:6839 次
发布时间:2019-06-26

本文共 4326 字,大约阅读时间需要 14 分钟。

hot3.png

      ThreadLocal 让每个线程可以保留一份变量的私有"版本" 。
早在
JDK 1.2
的版本中就提供
java.lang.ThreadLocal
ThreadLocal
为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。
ThreadLocal
并不是一个
Thread
,而是
Thread
的局部变量。当使用
ThreadLocal
维护变量时,
ThreadLocal
为每个使用该变量的线程提供独立的变量副本。

ThreadLocal的接口方法:

  1. void set(Object value):设置当前线程的线程局部变量的值。
  2. public Object get():该方法返回当前线程所对应的线程局部变量。
  3. public void remove():将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。

   需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

      protected Object initialValue():返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null

    在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal<T>

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本。

下面是一个多线程向一个表插入数据的例子:

package com.lucky.concurrent;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;public class ThreadLocalDemo extends Thread {	@Override	public void run() {		ThradTask.executeUpdate();	}	public static void main(String[] args) {		for (int i = 0; i < 900; i++) {			ThreadLocalDemo demo = new ThreadLocalDemo();			demo.start();		}	}}class ThradTask {	static String sql = "insert into job_log(id, jobtype, logdate, status, ext1, ext2, ext3, log_time) values (seq_job_log.nextval, 1, sysdate, 1, null, null, null, sysdate)";	public static void executeUpdate() {		Connection con = null;		try {			con = DbUtil.getConnection();			con.setAutoCommit(false); // 关闭自动提交事务(开启事务)			con.prepareStatement(sql).executeUpdate();			con.commit();		} catch (SQLException e) {                         e.printStackTrace();		} finally {			DbUtil.closeConnection();			System.out.println("insert success ");		}	}}class DbUtil {	private static Connection con;// 静态连接对象,全部对象共享一个	public static Connection getConnection() {		try {			Class.forName("oracle.jdbc.driver.OracleDriver");			con = DriverManager.getConnection(					"jdbc:oracle:thin:@xx.xx.xx.xx:1521:orcl", "dev_tc",					"123456");		} catch (Exception e) {			e.printStackTrace();		}		return con;	}	public static void closeConnection() {		if (con != null) {			try {				con.close();			} catch (SQLException e) {				e.printStackTrace();			}		}	}}
看结果:

数据库关闭的连接,这个错误跟 Connection 有关系,那我就将主要精力放在检查 Connection 相关的代码上吧。是不是 Connection 不应该是 static 的呢?我当初设计成 static 的主要是为了让 DBUtil 的 static 方法访问起来更加方便,用 static 变量来存放 Connection 也提高了性能啊。怎么搞呢?接着就是重构了DbUtil。看下面的代码。只贴出DbUtil的代码。

   

class DbUtil {	private static ThreadLocal
local = new ThreadLocal
(); public static Connection getConnection() { try { Connection localCon = local.get(); if (localCon == null) { Class.forName("oracle.jdbc.driver.OracleDriver"); localCon = DriverManager.getConnection( "jdbc:oracle:thin:@xx.xx.xx.xx:1521:orcl", "dev_tc", "123456"); local.set(localCon); } } catch (Exception e) { //获取链接报错,比如超过最大连接数则销毁当前任务。
<正常情况下是不能这样做>
Thread.currentThread().stop(); e.printStackTrace(); } return local.get(); } public static void closeConnection() { Connection con = local.get(); if (con != null) { try { con.close(); } catch (SQLException e) { e.printStackTrace(); }finally{ local.remove();//将当前线程局部变量的值删除,目的是为了减少内存的占用 } } }}
运行结果:

下面是另一个例子:

package test;import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadLocalTest {	private static class Task implements Runnable {		private static ThreadLocal
number = new ThreadLocal
() { @Override protected Integer initialValue() { return 0; } }; public int getNumber() { number.set(number.get() + 1); return number.get(); } @Override public void run() { try { Thread.sleep(new Random().nextInt(5000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + getNumber()); } } public void run() { ExecutorService pool = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { pool.execute(new ThreadLocalTest.Task()); } pool.shutdown(); } public static void main(String[] args) { new ThreadLocalTest().run(); }}

运行结果:每一个线程初始化值都是1。获得的结果就是static变量没有多线程共享。多线程安全。

此文章是学习了 这位大牛的而出世的。

下次继续写。先睡觉。

转载于:https://my.oschina.net/jielucky/blog/160613

你可能感兴趣的文章
C语言之基本运算及自动类型转换和强制类型转换
查看>>
docker私有仓库管理系统harbor的部署使用
查看>>
centos 编译安装gcc8.1
查看>>
ICS Protocol Dissection
查看>>
Linux的DHCP服务配置
查看>>
我的友情链接
查看>>
【挨踢人物传】李晨光:兴趣铸就专业,努力决定成败
查看>>
横向ListView
查看>>
mysql主从同步操作
查看>>
隐藏自己的进程
查看>>
全国省市数据
查看>>
判断文件夹大小并复制到另一个地方
查看>>
CISCO 路由器 HWIC-4ESW 配置案例
查看>>
1 张图秒懂 Nova 16 种操作 - 每天5分钟玩转 OpenStack(44)
查看>>
hostPath Volume - 每天5分钟玩转 Docker 容器技术(148)
查看>>
Liunx 终端 bash 提示符 修改 DIY
查看>>
jQuery 判断图片加载完毕例子
查看>>
Freemarker生成PDF
查看>>
IDC评述网:12月上旬全球域名解析服务商Top15
查看>>
Tomcat认证授权与简单的SSO
查看>>