• ThreadLocal 和 Countdaowlatch


    ThreadLocal 和 Countdaowlatch

    ThreadLocal

    ThreadLocal提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。

        public void set(T var1) {
            Thread var2 = Thread.currentThread();
            ThreadLocal.ThreadLocalMap var3 = this.getMap(var2);
            if (var3 != null) {
                var3.set(this, var1);
            } else {
                this.createMap(var2, var1);
            }
        }
    
    
     public T get() {
            Thread var1 = Thread.currentThread();
            ThreadLocal.ThreadLocalMap var2 = this.getMap(var1);
            if (var2 != null) {
                ThreadLocal.ThreadLocalMap.Entry var3 = var2.getEntry(this);
                if (var3 != null) {
                    Object var4 = var3.value;
                    return var4;
                }
            }
            return this.setInitialValue();
        }
    
    public void remove() {
            ThreadLocal.ThreadLocalMap var1 = this.getMap(Thread.currentThread());
            if (var1 != null) {
                var1.remove(this);
            }
    
        }
    

    ThreadLocal往往用来实现变量在线程之间的隔离

    创建一个ThreadLocal对象,指定存储的数据为integer,初始值为100

    package Thread;
    
    public class ThreadLocalTest {
    
        static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
            @Override
            protected Integer initialValue() {
                return 100;
            }
        };
    
        static class ADDThread extends Thread{
            @Override
            public void run() {
                Integer integer = threadLocal.get();
                System.out.println(Thread.currentThread().getName()+"----初始值----"+integer);
    
                integer +=100;
                System.out.println(Thread.currentThread().getName()+"----线程 操作int+100 ----");
    
                threadLocal.set(integer);
                System.out.println(Thread.currentThread().getName()+"----调用set存放新的integer到threadlocal,保存修改");
    
                System.out.println(Thread.currentThread().getName()+"----当前线程的副本值"+threadLocal.get());
    
            }
        }
    
        static class SubThread extends Thread{
            @Override
            public void run() {
                Integer integer = threadLocal.get();
                System.out.println(Thread.currentThread().getName()+"----初始值----"+integer);
            }
        }
        public static void main(String[] args) {
            new ADDThread().start();
            new SubThread().start();
        }
    }
    ================================================================
    Thread-0----初始值----100
    Thread-0----线程 操作int+100 ----
    Thread-0----调用set存放新的integer到threadlocal,保存修改
    Thread-0----当前线程的副本值200
    Thread-1----初始值----100
    

    ThreadLocal原理:

    ThreadLocal内部有一个内部类ThreadLocalMap;ThreadLocalMap的内部有一个Entry内部类,ThreadLocalMap内部类维护了一个Entry数组,Entry(类似Map.Entry)key是ThreadLocal,value是Object;每一个线程都有一个ThreadLocalMap的实例,这个ThreadLocalMap内部又有一个Entry数组,将threadLocal作为key获取每个线程中独立的副本,因为threadLocal可以有多个,所以Entry以数组的形式存放;

    static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
    

    img

    Countdaowlatch

    • countDownLatch是在java1.5被引入,跟它一起被引入的工具类还有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。
    • 存在于java.util.cucurrent包下。

    countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。

    是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

    //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
    public void await() throws InterruptedException { };   
    //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
    //将count值减1
    public void countDown() { };  
    

    实例:

    package Thread;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class CountDownLatchTest {
        public static void main(String[] args) {
            final CountDownLatch latch = new CountDownLatch(2);
            System.out.println("Main Thread start run....");
            // first thread run
            ExecutorService es1 = Executors.newSingleThreadExecutor();
            es1.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                        System.out.println("fist thread :" + Thread.currentThread().getName() + "run ..");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    latch.countDown();
                }
            });
            es1.shutdown();
            // second thread run
            ExecutorService es2 = Executors.newSingleThreadExecutor();
            es2.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("second Thread : " + Thread.currentThread().getName() + " run ");
                    latch.countDown();
                }
            });
            es2.shutdown();
            System.out.println("wait two thread finished");
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("main thread run !!");
        }
    }
    ===============================================
    Main Thread start run....
    wait two thread finished
    fist thread :pool-1-thread-1run ..
    second Thread : pool-2-thread-1 run 
    main thread run !!
    

    CountDownLatch的用法
    CountDownLatch典型用法1:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ,每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

    CountDownLatch典型用法2:实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。

  • 相关阅读:
    程序设计思维与实践 Week5 作业 (3/4/数据班)
    程序设计思维与实践 Week6 作业 (3/4/数据班)
    Effective C++笔记(更新中...)
    二叉树的序列化与反序列化
    矩阵乘法的顺序安排问题 Python简单实现
    Python 读写Excel文件 总结
    2019美赛D题 人员疏散模型Python编程
    函数绘图语言 西电编译原理大作业
    洛谷试炼场 动态规划专练
    2019 IEEEXtreme 13.0 Impact Factor 影响因子
  • 原文地址:https://www.cnblogs.com/AronJudge/p/15884479.html
Copyright © 2020-2023  润新知