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

 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. Orecle基本概述(1)

    Orecle1.什么是orecle及体系结构?* 全局数据库,指物理磁盘数据库,一个真实存在的磁盘目录.*用户: 用户在oracle里面是用来隔离数据的*表空间: 逻辑结构,不可视的,虚拟的,用户的数 ...

  2. 算法学习之剑指offer(六)

    题目1 题目描述 输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. import java.util.*; public cl ...

  3. Detours 劫持

    在使用 Detours 劫持之前必须得拥有这两个东西:detours.h 和 detours.lib. 为了这两个东西我真的是弄了大半天,本着自己动手丰衣足食的思想: 我去 GitHub 克隆了一份来 ...

  4. PHP each

    1.函数的作用:遍历数组元素 2.函数参数: @params array &$array 3.例子: <?php $arr = ['Boy','Girl']; while(list($k ...

  5. .Net Core 3.0 IdentityServer4 快速入门

    .Net Core 3.0 IdentityServer4 快速入门 一.简介 IdentityServer4是用于ASP.NET Core的OpenID Connect和OAuth 2.0框架. 将 ...

  6. opencv::直方图计算

    直方图概念 上述直方图概念是基于图像像素值,其实对图像梯度.每个像素的角度.等一切图像的属性值,我们都可以建立直方图.        这个才是直方图的概念真正意义,不过是基于图像像素灰度直方图是最常见 ...

  7. std::multiset

    Set.multiset都是集合类, 差别在与set中不允许有重复元素, multiset中允许有重复元素. sets和multiset内部以平衡二叉树实现.   multiset 多重集合容器是一个 ...

  8. 微信小程序实现九宫格切图,保存功能!

    效果如下图: 代码如下: <view class='sudoku'> <scroll-view scroll-x scroll-y class='canvas-box'> &l ...

  9. 玩转PubSubClient MQTT库

    1.前言     在ESP8266学习系列中,博主一直使用HTTP协议.HTTP连接属于短连接,而在物联网应用中,广泛应用的却是MQTT协议.所以,本篇我们将学习Arduino平台上的MQTT实现库 ...

  10. ios 11 系统CPU过高,xib中textfield使用导致出过高

    ios11 发布之后,作为开发肯定是第一时间进行了升级测试,全新的系统不免会带来这样那样的问题.项目中使用xib的小伙伴们会发现,项目的cpu使用率非常高,尤其是初始化的时候,并没有线程的操作,CPU ...