zoukankan      html  css  js  c++  java
  • Java 线程安全

    1. 什么是线程安全?

      可变资源(内存)间线程共享。

    2. 如何实现线程安全?

    • 不共享资源;
    • 共享不可变资源;
    • 共享可变资源:
      • 可见性;
      • 操作原子性;
      • 禁止重排序;

      1. 不共享资源

        1. 可重入函数:函数体内部不涉及任何外部变量;

    // 可重入函数
    public static int addTwo(int num) {
        return  num + 3;
    }

        2. 使用ThreadLoacl:

    final static ThreadLocal<String> mThreadLocal = new ThreadLocal<>();
    
    public static void test() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                mThreadLocal.set(UUID.randomUUID().toString());
    
                System.out.println(Thread.currentThread().getName() + " -- token : " + mThreadLocal.get());
            }
        };
    
        for (int idx = 0; idx < 3; idx++) {
            Thread thread = new Thread(runnable);
            thread.start();
        }
    }

       上面的结果就是每个线程都有自己的副本,输出的值也不相同。

      ThreadLocal作用及实现原理:

      ThreadLocal作用是用于线程间数据隔离,ThreadLocal是线程内部数据存储类,通过ThreadLocal将数据存储在指定线程中,存储后只能通过指定线程获取数据,其它线程是获取不到数据的。ThreadLocal是一个Map(ThreadLocalMap),Key是线程对象Thread.currentThread,值为存储的数据,在Hander的Looper类中的ThreadLocal存储的是Looper对象。

      在Looper中ThreadLocal是静态常量存储于静态存储区,线程中工作内存中使用的是ThreadLocal的主内存的副本,但是由于ThreadLocal是一个Map对象,Key又是线程(Thread.currentThread),只能通过指定线程获取ThreadLocal中的数据,所以,做到了线程间数据隔离互不影响。

    /**
     * Returns the value in the current thread's copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread's value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    
    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

      通过ThreadLocal源码中get()和set()方法,操作的变量是ThreadLocalMap。

      ThreadLocalMap的创建:

        /**
         * Get the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param  t the current thread
         * @return the map
         */
        ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    
        /**
         * Create the map associated with a ThreadLocal. Overridden in
         * InheritableThreadLocal.
         *
         * @param t the current thread
         * @param firstValue value for the initial entry of the map
         */
        void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }

      ThreadLocalMap就是一个Map,而向Map中存储数据的key是Thread的this(map.set(this, value);),就是将值存储到线程上的,就是通过Map将thread的this和value绑定。

      ThreadLocal使用建议:

      • 声明为全局静态final变量;
      • 避免存储大量对象;
      • 使用完后及时移除对象;

      2. 共享不可变资源

        使用final关键字

      3. 共享可变资源

        1. 禁止重排序特性;

        2. 可见性:

          使用finalvolatile关键字:

          final:1. 修饰变量不可被修改;2. 修饰类不可被继承;3. 修饰方法不可被覆写;4. 禁止重排序特性;

          volatile:1. 可见性 -- 多线程操作时,其中一个线程修改了volatile修饰的变量,会通知其它线程变量改变;2. 禁止重排序;

          PS:每个线程都有自己的工作内存,工作内存将主内存变量copy到工作内存后,再执行操作。所以,导致了多线程时变量数据不一致性。

          2. 加锁:锁释放后强制将缓存数据刷新到主内存。

        3. 操作原子性:加锁。

  • 相关阅读:
    HDU 2602
    ZOJ 1074 最大子矩阵和
    POJ 3903
    最大子段和
    HDU 1052
    CodeForces 18C
    CodeForces 546B-Soldier and Badges
    UVA 11462-Age sort
    Codeforces Round #326 (Div. 2)-Duff in Love
    Codeforces Round #327 (Div. 2)-Wizards' Duel
  • 原文地址:https://www.cnblogs.com/naray/p/13028584.html
Copyright © 2011-2022 走看看