zoukankan      html  css  js  c++  java
  • 10.ThreadLocal

    
    /**
     * - void set(Object value)设置当前线程的线程局部变量的值。
     * - public Object get()该方法返回当前线程所对应的线程局部变量。
     * - public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。
     *   需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
     * - protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。
     *   这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
     */
    public class ThreadLocalDemo extends Thread{
        private Res res;
    
        public ThreadLocalDemo(Res res) {
            this.res = res;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName()+"-i:"+i+"-num:"+res.getNum());
            }
        }
        public static void main(String[] args){
            Res res = new Res();
            new ThreadLocalDemo(res).start();
            new ThreadLocalDemo(res).start();
            new ThreadLocalDemo(res).start();
        }
        //Thread-0-i:0-num:1
        //Thread-0-i:1-num:2
        //Thread-0-i:2-num:3
        //Thread-1-i:0-num:1
        //Thread-1-i:1-num:2
        //Thread-1-i:2-num:3
        //Thread-2-i:0-num:1
        //Thread-2-i:1-num:2
        //Thread-2-i:2-num:3
    }
    
    class Res{
        public static Integer count = 0;
        public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
            @Override
            protected Integer initialValue() {
                return 0;
            }
        };
        public Integer getNum(){
            int count = threadLocal.get() + 1;
            threadLocal.set(count);
            return count;
        }
    }
    
    /**
     * 如果你创建了 一个 ThreadLocal 变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。
     * 当多个线程操作这个变量时,实际操作的是自己本地内存里面的变量,从而避免了线程安全问题
     */
    public class ThreadLocalDemo {
        static ThreadLocal<String> local = new ThreadLocal<>();
        static void print(String s){
            System.out.println(s+":"+local.get());
            local.remove();
        }
        public static void main(String[] args){
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    local.set("threadA");
                    print("threadA");
                    System.out.println("threadA remove after:"+ local.get());
                }
            });
            Thread threadB = new Thread(new Runnable() {
                @Override
                public void run() {
                    local.set("threadB");
                    print("threadB");
                    System.out.println("threadB remove after:"+ local.get());
                }
            });
            threadA.start();
            threadB.start();
            //threadB:threadB
            //threadA:threadA
            //threadB remove after:threadB
            //threadA remove after:threadA
    
            //执行local.remove();
            //threadA:threadA
            //threadB:threadB
            //threadA remove after:null
            //threadB remove after:null
        }
    }
    
    public class ThreadLocalDemo2 {
        static ThreadLocal<String> local = new ThreadLocal<>();
        public static void main(String[] args){
            local.set("hello");
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("thread:"+local.get());
                }
            });
            threadA.start();
            System.out.println("main:"+local.get());
            //thread:null
            //main:hello
            //同一个 ThreadLocal 变量在父线程中被设置值后, 在子线程中是获取不到的。
            //因为在子线程 threadA 里面调用 get 方法时当前线程 为 threadA 线程,而这里调用 set 方法设置线程变量的是 main 线程,
            // 两者是不同的线程,自然子线程访问时返回 null
        }
    }
    
    /**
     * InheritableThreadLocal
     * 子线程获取父线程的threadlocal变量
     */
    public class ThreadLocalDemo3 {
        static ThreadLocal<String> local = new InheritableThreadLocal<>();
        public static void main(String[] args){
            local.set("hello");
            Thread threadA = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("thread:"+local.get());
                }
            });
            threadA.start();
            System.out.println("main:"+local.get());
            //main:hello
            //thread:hello
            //当父线程创建子线程时,构造函数会把父线程中 inheritableThreadLocals 变量里面的本地变量复制一份保存到子线程的 inheritableThreadLocals 变量里面
        }
    }
    
    

    简单使用

    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ParseDate{
        private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        public static class Parse implements  Runnable{
            int i = 0;
            public Parse(int i) {
                this.i = i;
            }
    
            @Override
            public void run() {
                try {
                    Date t = sdf.parse("2019-01-10 19:12:" + i % 60);
                    System.out.println(i+":"+t);
                }catch (ParseException e){
                    e.printStackTrace();
                }
            }
        }
        public static void main(String[] args){
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            for (int i = 0; i < 1000; i++) {
                executorService.execute(new Parse(i));
            }
        }
        //Exception in thread "pool-1-thread-121" Exception in thread "pool-1-thread-123" Exception in thread "pool-1-thread-120" java.lang.NumberFormatException: multiple points
        //	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
        //	at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
        //	at java.lang.Double.parseDouble(Double.java:538)
    
        //SimpleDateFormat.parse()方法并不是线程安全的,因此在线程池中共享这个对象必然导致错误
    
    }
    
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 为每一个线程分配不同的对象,需要在应用层面保证,ThreadLocal只是起到了简单的容器作用
     */
    public class ParseDate2 {
        static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>();
        public static class Parse implements  Runnable{
            int i = 0;
            public Parse(int i) {
                this.i = i;
            }
    
            @Override
            public void run() {
                try {
                    if (t1.get()==null){
                        t1.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
                    }
                    Date t = t1.get().parse("2019-01-10 19:12:" + i % 60);
                    System.out.println(i+":"+t);
                }catch (ParseException e){
                    e.printStackTrace();
                }
            }
        }
        public static void main(String[] args){
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            for (int i = 0; i < 1000; i++) {
                executorService.execute(new Parse(i));
            }
        }
    }
    
  • 相关阅读:
    easy Html5 Jquery Mobile之ToolBars(Header and Footer)
    Windows Phone7 性能
    easy Html5 Jquery Mobile之Buttons
    开篇,从这里开始。
    SkyDrive APIs——用户登录和APP授权(2)
    Windows Phone的强大语音控制,让你的Phone大秀一把
    SkyDrive APIs之——操作文件和文件夹(3)
    Mango in my mind 之 Live Tile
    SkyDrive APIs——搭建环境(1)
    windows10安装redis
  • 原文地址:https://www.cnblogs.com/fly-book/p/11367548.html
Copyright © 2011-2022 走看看