并发编程:ThreadLocal与单例模型

ThreadLocal:线程局部变量,是一种多线程之间并发访问变量的解决方案。与synchronized等加锁的方式不同,ThreadLocal完全不提供锁,其采用以空间换时间的思想,为每个线程的变量提供独立副本以保障线程安全。在并发不是很高的业务场景下,加锁较之会性能更好,但ThreadLocal作为一套与锁完全无关的线程安全解决方案,在高并发量或者竞争激烈的场景下,其可以在一定程度上减少锁竞争。下面给出一小段例子:

package _08_ThreadLocal与单例模型;

public class ThreadLocal01 {
	public static ThreadLocal<String> thread = new ThreadLocal<String>();
	@SuppressWarnings("static-access")
	public void getThread() {
		System.err.println(Thread.currentThread().getName()+":"+this.thread.get());
	}
	public void setThread(String value) {
		thread.set(value);
	}
	public static void main(String[] args) {
		final ThreadLocal01 thread01 = new ThreadLocal01();
		Thread thread1 = new Thread(new Runnable() {
			@Override	
			public void run() {
				thread01.setThread("张三");
				thread01.getThread();
				}
			},"thread1");
		Thread thread2 = new Thread(new Runnable() {
			@Override	
			public void run() {
					try {
						Thread.sleep(3*1000);
						thread01.getThread();
					} catch (InterruptedException e) {
						System.err.println(e.getMessage());
					}
				}
			},"thread2");
		thread1.start();
		thread2.start();
	}
}

运行起来,显然,只有线程thread1输出值“张三”,而线程thread2输出为null,下面进行源码分析:

代码段A:

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

当执行“thread.get()”时进入上面A,A先是获取当前线程,然后进行getMap(t)获取ThreadLocalMap,此处thread1的Map存在值“张三”,而thread2则是初次进入,其Map此次需要先进行初始化,其值为空。

ThreadLocalMap的说明为:

        /**
         * The entries in this hash map extend WeakReference, using its main ref field as 
           the key (which is always a ThreadLocal object).  
         * Note that null keys (i.e. entry.get() == null) mean that the key is no longer 
           referenced, so the entry can be expunged from table. 
         * Such entries are referred to as "stale entries" in the code that follows.
         */

thread1获得其ThreadLocalMap后通过getEntity(this)获取其对应的Entity(Entity为ThreadLocalMap-Object键值对),然后返回其对应的value(即“张三”),若没有对应的ThreadLocalMap,则返回setInitialValue()的返回值(即初始化一个ThreadLocalMap)。

setInitialValue的源码:

    /**
     * Variant of set() to establish initialValue. 
     * Used instead of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

ThreadLocal与单例模式的结合:

单例模式分为懒汉模式和饿汉模式,与ThreadLocal的结合主要采用dubble checkInstance和static inner class两种方式。下面给出两段小例子进行演示。

dubble checkInstance方式:

public class DoubleSingleton {
	private static DoubleSingleton ds;
	
	public static DoubleSingleton getDs() {
		if(ds == null) {
			try {
				System.err.println("初始化对象");
				Thread.sleep(2*1000);
			}catch(Exception e) {
				System.err.println(e.getMessage());
			}
			synchronized (DoubleSingleton.class) {
				if(ds == null) {
					ds = new DoubleSingleton();
				}
			}
		}
		return ds;
	}

	public static void main(String[] args) {
		Thread thread1 = new Thread(new Runnable() {
			@Override
			public void run() {
				System.err.println(DoubleSingleton.getDs().hashCode());
			}
		},"thread1");
		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
				System.err.println(DoubleSingleton.getDs().hashCode());
			}
		},"thread2");
		Thread thread3 = new Thread(new Runnable() {
			@Override
			public void run() {
				System.err.println(DoubleSingleton.getDs().hashCode());
			}
		},"thread3");
		thread1.start();
		thread2.start();
		thread3.start();
	}
}

static inner class方式:

public class Singleton {
	private static class InnerSingleton{
		private static Singleton single = new Singleton();
	}
	public static Singleton getInstance() {
		return InnerSingleton.single;
	}
}

猜你喜欢

转载自blog.csdn.net/txd2016_5_11/article/details/83098001