zoukankan      html  css  js  c++  java
  • Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类

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

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

  • 相关阅读:
    Linux下vi的用法
    C++程序设计语言编程风格演变史(转载)
    软件项目经理必备素质(转)
    DES加密算法的实现
    世界编程大赛一等奖作品
    AStar算法的原理及应用
    一个DirectX使用的例子
    ConsolePlayer
    自制贪吃蛇游戏
    关于安装 DirectX SDk Dec 2005 后无法编译DirectShow应用程序的问题
  • 原文地址:https://www.cnblogs.com/wq3435/p/6034629.html
Copyright © 2011-2022 走看看