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

 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. PMP(第六版)中的控制账户、规划包、工作包

    PMP(第六版)中的控制账户.规划包.工作包 控制账户是一个管理控制点,在该控制点上,把范围.预算和进度加以整合,并与挣值比较,以测量绩效.控制账户拥有2个或以上的工作包,但每个工作包只与一个控制账户 ...

  2. Tensorflow从开始到放弃

    刚刚开始学习神经网络,使用tensorflow,发现不会上网真的是个大坑. 在此记录一路以来已经遇到的坑和即将遇到的坑(非技术问题). 我是不会放弃的. Q:能够访问的tensorflow官网: A: ...

  3. 阿里云 centos7.X mysql数据库安装、配置

    前言 1024阿里云搞活动,ecs云服务新用户促销活动,活动连接就不贴了,买了之后暂时不知道要做啥,想着先安装mysql数据库. 步骤 root用户登录进来 1.配置mysql的yum源,yum lo ...

  4. markdown数学公式大全

    目录 Cmd Markdown 公式指导手册 一.公式使用参考 1.如何插入公式 2.如何输入上下标 3.如何输入括号和分隔符 4.如何输入分数 5.如何输入开方 6.如何输入省略号 7.如何输入矢量 ...

  5. 云计算 docker 容器使用命令

    docker 使用命令: docker version 查看docker版本号 vi /etc/docker/daemon.json { "registry-mirrors": [ ...

  6. 告别10kb/s的Github访问速度

    由于种种原因,国内访问Github的体验一直不是很好.本文通过优化DNS缓存的方式,避免浏览器直接解析Github域名,来改善Github的访问速度. 本文分为如下三个部分: 通过IP地址查询获取访问 ...

  7. 面试又被 Java 基础难住了?推荐你看看这篇文章。

    本文已经收录自 JavaGuide (59k+ Star):[Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识. 1. 面向对象和面向过程的区别 面向过程 :面向过程性能比面 ...

  8. 包管理工具-yum

    yum介绍 yum(全称为 Yellow dog Updater, Modified)是一个在 Fedora和 RedHat 以及 CentOS 中的 Shell 前端软件包管理器.基于 RPM 包管 ...

  9. python中根据时间获取周数,通过周数获取时间

    # 时间## 时间和周数 import time import datetime # 获取今天是第几周 print(time.strftime('%W')) # 获取当前是周几(0-6,0代表周一) ...

  10. fenby C语言P21

    数据类型 数组名字[个数]: #include <stdio.h> int main(){ int a[8]; float b[9]; char c[10]; return 0;}