在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

Java 中ThreadLocal类详解

2016-8-29 13:51| 发布者: zhangjf| 查看: 636| 评论: 0

摘要: ThreadLocal类,代表一个线程局部变量,通过把数据放在ThreadLocal中,可以让每个线程创建一个该变量的副本。也可以看成是线程同步的另一种方式吧,通过为每个线程创建一个变量的线程本地副本,从而避免并发线程同时 ...

ThreadLocal类,代表一个线程局部变量,通过把数据放在ThreadLocal中,可以让每个线程创建一个该变量的副本。也可以看成是线程同步的另一种方式吧,通过为每个线程创建一个变量的线程本地副本,从而避免并发线程同时读写同一个变量资源时的冲突。

示例如下:

  1. import java.util.Random;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.Executors;
  4. import java.util.concurrent.TimeUnit;
  5. import com.sun.javafx.webkit.Accessor;
  6. public class ThreadLocalTest {
  7. static class ThreadLocalVariableHolder {
  8. private static ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
  9. private Random random = new Random();
  10. protected synchronized Integer initialValue() {
  11. return random.nextInt(10000);
  12. }
  13. };
  14. public static void increment() {
  15. value.set(value.get() + 1);
  16. }
  17. public static int get() {
  18. return value.get();
  19. }
  20. }
  21. static class Accessor implements Runnable{
  22. private final int id;
  23. public Accessor(int id) {
  24. this.id = id;
  25. }
  26. @Override
  27. public void run() {
  28. while (!Thread.currentThread().isInterrupted()) {
  29. ThreadLocalVariableHolder.increment();
  30. System.out.println(this);
  31. Thread.yield();
  32. }
  33. }
  34. @Override
  35. public String toString() {
  36. return "#" + id + ": " + ThreadLocalVariableHolder.get();
  37. }
  38. }
  39. public static void main(String[] args) {
  40. ExecutorService executorService = Executors.newCachedThreadPool();
  41. for (int i = 0; i < 5; i++) {
  42. executorService.execute(new Accessor(i));
  43. }
  44. try {
  45. TimeUnit.MICROSECONDS.sleep(1);
  46. } catch (InterruptedException e) {
  47. e.printStackTrace();
  48. }
  49. executorService.shutdownNow();
  50. }
  51. }
复制代码

运行结果:

  1. #1: 9685
  2. #1: 9686
  3. #2: 138
  4. #2: 139
  5. #2: 140
  6. #2: 141
  7. #0: 5255
  8. 。。。
复制代码

由运行结果可知,各线程都用于各自的Local变量,并各自读写互不干扰。

ThreadLocal共提供了三个方法来操作,set,get和remove。

在Android 中的Looper,即使用了ThreadLocal来为每个线程都创建各自独立的Looper对象。

  1. public final class Looper {
  2. private static final String TAG = "Looper";
  3. // sThreadLocal.get() will return null unless you've called prepare().
  4. static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
  5. private static void prepare(boolean quitAllowed) {
  6. if (sThreadLocal.get() != null) {
  7. throw new RuntimeException("Only one Looper may be created per thread");
  8. }
  9. sThreadLocal.set(new Looper(quitAllowed));
  10. }
  11. 。。。
  12. }
复制代码

当某个线程需要自己的Looper及消息队列时,就调用Looper.prepare(),它会为线程创建属于线程的Looper对象及MessageQueue,并将Looper对象保存在ThreadLocal中。

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-7 06:17

Copyright 2015-2025 djqfx

返回顶部