Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类
发布日期:2021-07-12 08:49:36 浏览次数:4 分类:技术文章

本文共 8932 字,大约阅读时间需要 29 分钟。

1.线程范围内共享变量

  

1.1 前奏:

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

  

public class ThreadScopeShareData {    static Map
dataMap = new HashMap
(); 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
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
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
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( hook)

  addShutdownHook( 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);            }        }    }}

 

 

 

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

转载于:https://www.cnblogs.com/wq3435/p/6034629.html

转载地址:https://blog.csdn.net/ankan7400/article/details/102088971 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Java多线程与并发库高级应用-java5线程并发库
下一篇:Java多线程与并发库高级应用-传统线程同步通信技术

发表评论

最新留言

很好
[***.229.124.182]2024年03月10日 08时01分57秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

linux磁盘的命令是,linux磁盘相关的命令 2019-04-21
linux服务器 缓存,Linux服务器内存使用分析及内存缓存 2019-04-21
linux查进程内存问题,关于linux 查看服务进程内存,cpu,内存占用的一些基础命令... 2019-04-21
linux英文包安装教程视频,Linux源码包安装过程讲解 2019-04-21
linux 关闭rsync服务器,linux下配置rsync服务器和实时同步 2019-04-21
linux初始化TCP服务失败,深入Linux系统追踪TCP初始化 2019-04-21
arch Linux添加源,在Arch Linux系统中使用Archlinuxcn源(清华源)的方法 2019-04-21
私人linux远程连接,Linux远程连接 - osc_5g1gl9wp的个人空间 - OSCHINA - 中文开源技术交流社区... 2019-04-21
windows文件迁移到linux,从Windows到Linux迁移之文件服务器(Samba和AD完美结合) 2019-04-21
linux下vi编辑器的命令大全,linux下VI编辑器命令大全(超级完整版) 2019-04-21
linux结构体数组的定义数组,task_struct结构体中的run_list和array域 2019-04-21
C语言极坐标转直角坐标,C语言实现直角坐标转换为极坐标的方法 2019-04-21
16F877A和24C02通信汇编语言,PIC16f877A读写24c02程序 2019-04-21
用c语言编写小于n的所有素数,关于求N以内素数的一点小问题(N小于一亿) 2019-04-21
华为100万部鸿蒙,2019年Q4发布 华为100万部鸿蒙OS手机已开测 2019-04-21
android+大富翁+局域网,【图片】大富翁6局域网(LAN)多人联机教程(求精)_大富翁吧_百度贴吧... 2019-04-21
rn webview加载本地静态html,React Native - Webview 加载本地文件 2019-04-21
vscode 不能使用中文输入法_vscode中vim插件设置 2019-04-21
fi sap 凭证冲销 稅_SAP中的成本要素 2019-04-21
kangle主机怎么配置MySQL_kangle web服务+easypanel主机控制面板快速搭建网站和数据库以及管理空间详细教程... 2019-04-21