当多个线程操作同一个共有数据时,一个线程对共有数据的改变会影响到另一个线程。比如下面这个例子:两个线程调用同一个对象的的方法,一个线程的执行结果会影响另一个线程。

 package com.sky.thread;

 public class TestThreadLocal {
public static void main(String[] args) {
final ThreadLocalBiz biz = new ThreadLocalBiz();
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
biz.add(); }
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
biz.add(); }
}
}).start();
}
} class ThreadLocalBiz {
private int num = 0; public synchronized void add() {
num++;
System.out.println("线程:" + Thread.currentThread().getName() + "num:"
+ num);
}
}

线程结果互相影响

执行的结果是:

线程:Thread-0num:1
线程:Thread-1num:2
线程:Thread-0num:3
线程:Thread-1num:4

执行结果

可见,Thread-0执行完以后,num的值是1。当Thread-1开始执行时,num的值对它而言是1而不是一开始的0,所以在Thread-1执行完以后,num的值变成了2。

如果我们想让两个线程在操作同一个共有数据时,互相的操作结果互不影响该怎么办?

这个时候可以使用ThreadLocal。先看下面的代码:

 package com.sky.thread;

 public class TestThreadLocal {

     public static void main(String[] args) {
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ThreadLocalBiz.getBiz().add(); }
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ThreadLocalBiz.getBiz().add(); }
}
}).start();
}
} class ThreadLocalBiz {
private int num = 0;
public static ThreadLocal<ThreadLocalBiz> LocalBiz = new ThreadLocal<ThreadLocalBiz>(); private ThreadLocalBiz(){}
public static ThreadLocalBiz getBiz(){
ThreadLocalBiz biz = LocalBiz.get();
if (biz == null) {
biz = new ThreadLocalBiz();
LocalBiz.set(biz);
}
return biz;
}
public void add() {
num++;
System.out.println("线程:" + Thread.currentThread().getName() + ",num:"
+ num);
} }
线程:Thread-0,num:1
线程:Thread-1,num:1
线程:Thread-0,num:2
线程:Thread-0,num:3
线程:Thread-1,num:2

执行结果

这段代码的基本思路是,为不同的线程创建单独的实例。比如上面这段代码,有两个线程调用的ThreadLocalBiz的add方法,那么一共创建的两个ThreadLocalBiz实例。每个线程操作自己的专属实例,自然就不会相互干扰了。

在这段代码中,getBiz和add方法都没有加synchronized,就是因为单个实例只对应单个线程,不存在并发问题,自然也就不用加互斥锁了。

现在来仔细说说ThreadLocal。

ThreadLocal相当于一个Map。以当前线程作为key。

下面的代码

ThreadLocal<ThreadLocalBiz> LocalBiz = new ThreadLocal<ThreadLocalBiz>();
LocalBiz.set(new ThreadLocalBiz());
LocalBiz.get();

就相当于

Map<Thread, ThreadLocalBiz> ThreadMap = new HashMap<Thread, ThreadLocalBiz>();
ThreadMap.put(Thread.currentThread(), new ThreadLocalBiz());
ThreadMap.get(Thread.currentThread());

可见,ThreadLocal完全可以被Map代替。java只是代为封装了一下。

java多线程与线程并发四:线程范围内的共享数据的更多相关文章

  1. “全栈2019”Java多线程第三十四章:超时自动唤醒被等待的线程

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  2. Java多线程学习(八)线程池与Executor 框架

    目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...

  3. Java多线程-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier

    Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-从一个错误的双重校验锁 ...

  4. Java 多线程基础(五)线程同步

    Java 多线程基础(五)线程同步 当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题. 要解决上述多线程并发访问一个资源的安全性问题,Java中提供了同步机制 ...

  5. Java多线程基础:进程和线程之由来

    转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...

  6. “全栈2019”Java多线程第十三章:线程组ThreadGroup详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. 1、Java多线程基础:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  8. Java 多线程基础(六)线程等待与唤醒

    Java 多线程基础(六)线程等待与唤醒 遇到这样一个场景,当某线程里面的逻辑需要等待异步处理结果返回后才能继续执行.或者说想要把一个异步的操作封装成一个同步的过程.这里就用到了线程等待唤醒机制. 一 ...

  9. Java 多线程基础(十一)线程优先级和守护线程

    Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...

  10. Java多线程之~~~使用Exchanger在线程之间交换数据[这个结合多线程并行会有解决很多问题]生产者消费者模型

    http://blog.csdn.net/a352193394/article/details/39503857  Java多线程之~~~使用Exchanger在线程之间交换数据[这个结合多线程并行会 ...

随机推荐

  1. LeetCode初级算法--字符串01:反转字符串

    LeetCode初级算法--字符串01:反转字符串 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...

  2. vue-cli中使用jquery

    一.安装依赖 npm install jquery --save 二.全局导入(必须先安装依赖) 第一步 在webpack.base.conf.js里加入(新版的可能找不到这个文件,你可以npm in ...

  3. badboy录制脚本

    第一步:介绍badboy工具 1.1: 页面功能分析: 1. 界面视图,模拟浏览器,能够进行操作 2. 需要录制脚本的URL 3. 点击运行URL 4. Summary:运行的各指标,响应时间,成功事 ...

  4. Jmeter结构体系及运行顺序

    一:jmeter运行原理: jmeter时以线程的方式来运行的(由于jmeter是java开发的所以是运行在JVM虚拟机上的,java也是支持多线程的) 二:jmeter结构体系 1.取样器smapl ...

  5. Roadmap of FE

    未完待补充......

  6. [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers

    本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...

  7. git 删除未提交的文件

    git checkout . && git clean -xdf

  8. python-json与字典的区别

    1.字典的类型是字典dict,是一种数据结构:json的类型是字符串str,json是一种格式: 接口测试是传参数payload时有时候是传的字符串,应该将payload的类型改为json  这点要注 ...

  9. Uipath创建文件夹

    东京IT青年前线 http://www.rpatokyo.com/ Uipath创建文件夹 使用Create Folder进行文件夹的创建 这里可以指定相对路径和绝对路径 如果没有指定文件夹的绝对路径 ...

  10. Python 调用图灵机器人 API

    ''' Python3''' import requests #导入requests库 import json #导入json库 key = '3119f1e3610f42c5977ea73c4097 ...