1.线程范围内共享变量

  

1.1 前奏:

使用一个Map来实现线程范围内共享变量

  

public class ThreadScopeShareData {

    static Map<Thread, Integer> dataMap = new HashMap<Thread, Integer>();

    public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(); // 获取一个随机整数
System.out.println(Thread.currentThread().getName()
+ " put data " + data);
dataMap.put(Thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
} static class A {
public void get() {
System.out.println(Thread.currentThread().getName() + " get data "
+ dataMap.get(Thread.currentThread()));
}
} static class B {
public void get() {
System.out.println(Thread.currentThread().getName() + "get data "
+ dataMap.get(Thread.currentThread()));
}
} }

  

1.2 ThreadLocal类实际上就是一种map

/**
* ThreadLocal 类 这里ThreadLocal存放一个变量,如果有多个变量, 可以先将多个变量封装为一个对象
*
* @author Administrator
*
*/
public class ThreadLocalTest {
static ThreadLocal<Integer> x = new ThreadLocal<>(); // public static void main(String[] args) { //
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(); // 获取一个随机整数
System.out.println(Thread.currentThread().getName()
+ " put data " + data);
x.set(data);
new A().get();
new B().get();
}
}).start();
}
} static class A {
public void get() {
System.out.println(Thread.currentThread().getName() + " get data "
+ x.get());
}
} static class B {
public void get() {
System.out.println(Thread.currentThread().getName() + "get data "
+ x.get());
}
} }

 2.线程范围内共享多个变量,可以将多个变量封装为一个对象

/**
* ThreadLocal 类 这里ThreadLocal存放一个变量,如果有多个变量, 可以先将多个变量封装为一个对象
*
* @author Administrator
*
*/
public class ThreadLocalTest {
static ThreadLocal<Integer> x = new ThreadLocal<>(); // public static void main(String[] args) { //
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(); // 获取一个随机整数
System.out.println(Thread.currentThread().getName()
+ " put data " + data);
x.set(data);
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();//获取与线程绑定的对象
myData.setName("name"+data);
myData.setAge(data);
System.out.println(Thread.currentThread().getName()
+ " put Object " + "name: "+myData.getName()+","+" age: "+myData.getAge());
new A().get();
new B().get();
}
}).start();
}
} static class A {
public void get() {
System.out.println(Thread.currentThread().getName() + " get data "
+ x.get());
MyThreadScopeData instance = MyThreadScopeData.getThreadInstance(); //直接获取与该线程相关的对象
System.out.println(Thread.currentThread().getName() + " get Object "
+ "name: "+instance.getName()+","+" age: "+instance.getAge());
}
} static class B {
public void get() {
System.out.println(Thread.currentThread().getName() + "get data "
+ x.get());
MyThreadScopeData instance = MyThreadScopeData.getThreadInstance(); //直接获取与该线程相关的对象
System.out.println(Thread.currentThread().getName() + " get Object "
+ "name: "+instance.getName()+","+" age: "+instance.getAge());
}
} } // 单例
class MyThreadScopeData { //类的实例是与线程相关的,那么类的设计就交由类自身完成,只要调用自然就是与线程有关的
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<>(); private MyThreadScopeData() { } public static MyThreadScopeData getThreadInstance() { // 线程间是相互独立的,这里不需要考虑同步
MyThreadScopeData instance = map.get();
if (instance == null) {
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
} private String name;
private Integer age; /**
* @return the name
*/
public String getName() {
return name;
} /**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
} /**
* @return the age
*/
public Integer getAge() {
return age;
} /**
* @param age
* the age to set
*/
public void setAge(Integer age) {
this.age = age;
} }

打印结果

Thread-1 put data -723086824
Thread-0 put data 772514756
Thread-1 put Object name: name-723086824, age: -723086824
Thread-0 put Object name: name772514756, age: 772514756
Thread-0 get data 772514756
Thread-1 get data -723086824
Thread-0 get Object name: name772514756, age: 772514756
Thread-1 get Object name: name-723086824, age: -723086824
Thread-0get data 772514756
Thread-1get data -723086824
Thread-0 get Object name: name772514756, age: 772514756
Thread-1 get Object name: name-723086824, age: -723086824

类的实例是与线程相关的,那么类的设计就交由类自身完成,只要调用自然就是与线程有关的  strust2的主要思想就是这么设计的

参看JAVA API

ThreadLocal有一个 remove()方法

可以移除与该线程相关的变量

remove()
Removes the current thread's value for this thread-local variable.

补充:

  虚拟机的对应类 Runtime ,中有一个方法 addShutdownHook(Thread hook)

  addShutdownHook(Thread hook)
  Registers a new virtual-machine shutdown hook.

  例如可以写一个发送邮件的线程Thread,当虚拟机挂掉之前会调用传入的Thread,发送一封邮件。

线程中是不是也应该有这种机制,当一个线程挂掉之前可以执行一个之前注册好的事件,或者有一个监听器在监听线程的状态,从而进行回调

在获取到线程挂掉的通知,就可以把该线程相关的变量全部remove获取clear掉

多个线程访问共享对象和数据的方式 (启用4个线程,其中2个线程对j加1,2个线程对j减1)

 如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如卖票系统可以这个做。

第一种方式:将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

public class MutilThreadShareData {

    public static void main(String[] args) {
final ShareData1 data1 = new ShareData1(); //两个线程操作同一个对象
for(int i = 0;i<2;i++){
new Thread(new Runnable1(data1)).start();
new Thread(new Runnable2(data1)).start();
}
}
static class Runnable1 implements Runnable{
private ShareData1 data1; public Runnable1(ShareData1 data1) {
this.data1 = data1;
}
@Override
public void run() {
data1.increment();
}
}
static class Runnable2 implements Runnable{
private ShareData1 data1; public Runnable2(ShareData1 data1) {
this.data1 = data1;
}
@Override
public void run() {
data1.decrement();
}
}
} class ShareData1{
private int j = 0; void increment(){
j++;
System.out.println(j);
}
void decrement(){
j--;
System.out.println(j);
} }

  第二种: 将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。

public class MutilThreadShareData {

    private static ShareData1 data1 = new ShareData1(); //两个线程操作同一个对象
public static void main(String[] args) {
for(int i = 0;i<2;i++){
new Thread(new Runnable() {
@Override
public void run() {
data1.increment();
}
}).start();
new Thread(new Runnable() { @Override
public void run() {
data1.decrement();
}
}).start();
}
}
} class ShareData1{
private int j = 0; void increment(){
j++;
System.out.println(j);
}
void decrement(){
j--;
System.out.println(j);
} }

第三种:

public class MutilThreadShareData {

    private static int j = 0;
public static void main(String[] args) {
for(int i = 0;i<2;i++){
new Thread(new Inc()).start();
new Thread(new Dec()).start();
}
}
static class Inc implements Runnable{
@Override
public void run() {
for(int i = 0;i<100;i++){
j++;
System.out.println(j);
}
}
}
static class Dec implements Runnable{
@Override
public void run() {
for(int i = 0;i<100;i++){
j--;
System.out.println(j);
}
}
}
}

一个外部类有两个内部类,两个内部类如何共享数据,都操作外部类的成员变量得到共享数据的目的

Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类的更多相关文章

  1. Java多线程与并发库高级应用-线程池

    线程池 线程池的思想  线程池的概念与Executors类的应用 > 创建固定大小的线程池 > 创建缓存线程池 > 创建单一线程池(如何实现线程死掉后重新启动?) 关闭线程池 > ...

  2. Java多线程与并发库高级应用-java5线程并发库

    java5 中的线程并发库 主要在java.util.concurrent包中 还有 java.util.concurrent.atomic子包和java.util.concurrent.lock子包 ...

  3. Java多线程与并发库高级应用-工具类介绍

    java.util.concurrent.Lock 1.Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互 ...

  4. Java多线程与并发库高级应用-Callable与Future的应用

    Callable这种任务可以返回结果,返回的结果可以由Future去拿 >Future取得的结果类型和Callable返回的结果类型必须一致,这是通过泛型来实现的. >Completion ...

  5. Java多线程与并发库高级应用-传统线程机制回顾

    1.传统线程机制的回顾 1.1创建线程的两种传统方式 在Thread子类覆盖的run方法中编写运行代码 // 1.使用子类,把代码放到子类的run()中运行 Thread thread = new T ...

  6. Java多线程与并发库高级应用-传统线程同步通信技术

    面试题: 子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着又 主线程循环100次,如此循环50次,请写出程序 /** * 子线程循环10次,接着主线程循环100次,接着又回到 ...

  7. Java多线程与并发库高级应用-传统线程互斥技术

     线程安全问题: 多个线程操作同一份数据的时候,有可能会出现线程安全问题.可以用银行转账来解释. 模拟线程安全问题 /** * 启动两个线程分别打印两个名字,名字按照字符一个一个打印 * * @aut ...

  8. Java多线程与并发库高级应用-面试题

    第一题:现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,程序只需要运行4秒即可打印完这些日 ...

  9. Java多线程与并发库高级应用-同步集合

    ArrayBlockingQueue LinkedBlockingQueue 数组是连续的一片内存 链表是不连续的一片内存  传统方式下用Collections工具类提供的synchronizedCo ...

随机推荐

  1. Openjudge 1.12-04

    04:最匹配的矩阵 查看 总时间限制:  1000ms 内存限制:  65536kB 描述 给定一个m*n的矩阵A和r*s的矩阵B,其中0 < r ≤ m, 0 < s ≤ n,A.B所有 ...

  2. 数据库 SQL语法一

    建立表语句 CREATE TABLE TABLENAME(COL_NAME1 TYPE,COL_NAME2 TYPE,......); 常用TYPE说明 INT 正数 CHAR(LENGTH) 定长字 ...

  3. Spring Security笔记:解决CsrfFilter与Rest服务Post方式的矛盾

    基于Spring Security+Spring MVC的web应用,为了防止跨站提交攻击,通常会配置csrf,即: <http ...> ... <csrf /> </ ...

  4. Burndown chart

    S型的燃尽图 在一次milestone开发过程中,开发者会持续编辑issue列表,每个issue都有自己的生命周期.燃尽图预期这些issues会被线性的消灭掉,所以从第一天直接到最后一天画个直线表示预 ...

  5. JavaScript的一些知识碎片(2)-反射-全局变量-回调

    JavaScript中的反射:编程语言中的反射原理都一样,就是通过操作metadata(描述语言的语言)来完成一些不具备反射功能的语言很难实现的功能.在静态语言中,反射是一个高大上的东西,比如在运行时 ...

  6. HoloLens开发手记 - Unity development overview 使用Unity开发概述

    Unity Technical Preview for HoloLens最新发行版为:Beta 24,发布于 09/07/2016 开始使用Unity开发HoloLens应用之前,确保你已经安装好了必 ...

  7. APP架子迁移指南(二)

    接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...

  8. css+div 浮动分块

    前段时间学过几天html,只是怀着了解的态度,能够读懂别人的页面,能够扒现成就行,一直没有自己动手去实践过,其实也不是没有实践过,前段时间扒了一个网页,想按照自己的要求来改,可后果是越改越乱.今天心血 ...

  9. JSON返回DateTime/Date('123123123')/解决办法

    Date.prototype.format = function (format) //author: meizz    {        var o = {            "M+& ...

  10. VC维含义

    VC维含义的个人理解 有关于VC维可以在很多机器学习的理论中见到,它是一个重要的概念.在读<神经网络原理>的时候对一个实例不是很明白,通过这段时间观看斯坦福的机器学习公开课及相关补充材料, ...