并发编程基础之ThreadLocal

Posted 格物致知

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程基础之ThreadLocal相关的知识,希望对你有一定的参考价值。

一:概念

在多线程并发访问的情况下,为了解决线程安全,一般我们会使用synchronized关键字,如果并发访问量不是很大,可以使用synchronized,

但是如果数据量比较大,我们可以考虑使用ThreadLocal,顾名思义,就是线程的本地存储,对于类中的成员变量,如果多个线程同时访问

就会存在线程安全问题,ThreadLocal提供给我们不同于synchronized的另外一种思路,就是把变量值在每个线程存储副本

如下示例:

/**
 * 
 */
package com.hlcui.main;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Administrator
 *
 */
public class ThreadLocalDemo {
	
	//保留变量在线程中的副本
	private ThreadLocal<String> threadLocal = new ThreadLocal<String>();
	
	private void set(String name) {
		threadLocal.set(name);
	}
	
	private String get() {
		return threadLocal.get();
	}
	
	public static void main(String[] args) {
		final ThreadLocalDemo demo = new ThreadLocalDemo();
		
		ExecutorService executors = Executors.newFixedThreadPool(2);
		executors.execute(new Runnable() {
			@Override
			public void run() {
				demo.set("tom");
				String threadName = Thread.currentThread().getName();
				System.out.println(threadName+":::"+demo.get());
			}
		});
		
		executors.execute(new Runnable() {
			@Override
			public void run() {
				demo.set("jack");
				String threadName = Thread.currentThread().getName();
				System.out.println(threadName+":::"+demo.get());
			}
		});
		
		executors.shutdown();
	}
}

  

运行结果:

pool-1-thread-1:::tom
pool-1-thread-2:::jack

  

通过结果可以看出同一个实例的同一个方法,不同的线程获取的结果是不一样的。

 

示例二:

测试5个线程计数:

/**
 * 
 */
package com.hlcui.main;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author Administrator
 *
 */
public class ThreadDemo2 {
	public static void main(String[] args) {
		ExecutorService executors = Executors.newFixedThreadPool(5);
		for (int i = 0; i < 5; i++) {
			executors.execute(new ThreadHolder(i));
		}
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		executors.shutdown();
	}

}

class ThreadHolder implements Runnable {

	private final int id;

	ThreadHolder(int i) {
		this.id = i;
	}

	private static ThreadLocal<Integer> tl = new ThreadLocal<Integer>() {
		Random r = new Random(47);
		public synchronized Integer initialValue() {
			return r.nextInt(100);
		}
	};

	public static void increment() {
		tl.set(tl.get() + 1);
	}

	@Override
	public void run() {
		System.out.println(this);
		ThreadHolder.increment();
		System.out.println(this);
	}
	
	public String toString() {
		return "id:::"+id+", "+tl.get();
	}

}

  

运行结果:

id:::0, 58
id:::1, 55
id:::2, 93
id:::0, 59
id:::2, 94
id:::1, 56
id:::3, 61
id:::3, 62
id:::4, 61
id:::4, 62

  

以上是关于并发编程基础之ThreadLocal的主要内容,如果未能解决你的问题,请参考以下文章

并发编程系列之ThreadLocal实现原理

并发编程系列之ThreadLocal实现原理

Java并发编程之ThreadLocal源码分析

并发编程大师系列之:你真的了解ThreadLocal吗?

Java并发编程之ThreadLocal源码分析

Java 并发编程 -- 并发编程线程基础(线程创建与运行线程通知与等待join / sleep / yield方法线程中断线程上下文切换死锁守护线程与用户线程ThreadLocal)