现在的位置: 首页 > 综合 > 正文

多线程static变量的同步互斥

2013年10月18日 ⁄ 综合 ⁄ 共 3270字 ⁄ 字号 评论关闭

在多线程环境中,如果是static变量的话,因为这个类的所以实例都使用同一个static变量。考虑到线程安全的话,多线程控制的必须的。

实际在编写中有很多种写法,各种写法都有自己的特点。下面是参考网络资料整理的内容。感谢代码的原作者。

import java.util.Set;
import java.util.TreeSet;

//pattern 1:延迟初始化(非线程安全)
//pattern 2:static private方法初始化
//pattern 3:static initializer初始化
//pattern 4:double check idiom延迟初始化
//pattern 5:lazy initialization holder class idiom延迟初始化
//pattern 6:延迟初始化
public class ThreadTest {
	private static Set<String> set0;
	private static Set<String> set1 = initializeSet();
	private static Set<String> set2;
	private static volatile Set<String> set3;
	private static Set<String> set5;
	
	private static Set<String> initializeSet() {
		Set<String> init = new TreeSet<String>();
		for (int i = 0; i < 100; i++) {
			init.add("set1-" + i);
		}
		return init;
	}

	static {
		set2 = new TreeSet<String>();
		for (int i = 0; i < 100; i++) {
			set2.add("set2-" + i);
		}
	}

	/**
	 * 延迟初始化(非线程安全)。一般是不采用这种写法的。
	 * 
	 * @param obj 对象
	 * @return set0中是否包含字符串
	 */
	public boolean isContainsInSet0(String obj) {
		if (set0 == null) {
			set0 = new TreeSet<String>();
			for (int i = 0; i < 100; i++) {
				set0.add("set0-" + i);
			}
		}
		return set0.contains(obj);
	}

	/**
	 * static private方法初始化
	 * 
	 * @param obj 对象
	 * @return set1中是否包含字符串
	 */
	public boolean isContainsInSet1(String obj) {
		return set1.contains(obj);
	}

	/**
	 * static initializer初始化
	 * 
	 * @param obj 对象
	 * @return set2中是否包含字符串
	 */
	public boolean isContainsInSet2(String obj) {
		return set2.contains(obj);
	}

	/**
	 * double check idiom延迟初始化。在方法实现中也不是特别好的方法。
	 * 
	 * @param obj 对象
	 * @return set3中是否包含字符串
	 */
	public boolean isContainsInSet3(String obj) {
		Set<String> s = set3;
		if (s == null) {
			synchronized (ThreadTest.class) {
				s = set3;
				if (s == null) {
					s = new TreeSet<String>();
					for (int i = 0; i < 100; i++) {
						s.add("set3-" + i);
					}
					set3 = s;
				}
			}
		}
		return set3.contains(obj);
	}

	/**
	 * lazy initialization holder class idiom延迟初始化
	 * 
	 * @param obj 对象
	 * @return set4中是否包含字符串
	 */
	public boolean isContainsInSet4(String obj) {
		return Set4.set4.contains(obj);
	}

	private static class Set4 {
		static final Set<String> set4 = init();

		private static Set<String> init() {
			Set<String> s = new TreeSet<String>();
			for (int i = 0; i < 100; i++) {
				s.add("set4-" + i);
			}
			return s;
		}
	}

	/**
	 * 延迟初始化(每次都同期化,同期代价高。性能不好。)
	 * 
	 * @param obj 对象
	 * @return set5中是否包含字符串
	 */
	public boolean isContainsInSet5(String obj) {
		synchronized (ThreadTest.class) {
			if (set5 == null) {
				set5 = new TreeSet<String>();
				for (int i = 0; i < 100; i++) {
					set5.add("set5-" + i);
				}
			}
		}
		return set5.contains(obj);
	}
}

测试例子:

public class MultiThreadSample {
    public static void main(String[] args) {
        new T0().start();
        new T0().start();
         
        new T1().start();
        new T1().start();
         
        new T2().start();
        new T2().start();
         
        new T3().start();
        new T3().start();
         
        new T4().start();
        new T4().start();
         
        new T5().start();
        new T5().start();
    }
     
    private static class T0 extends Thread {
        public void run() {
            ThreadTest s = new ThreadTest();
            System.out.println("T0 : " + s.isContainsInSet0("set0-99"));               
        }
    }
     
    private static class T1 extends Thread {
        public void run() {
            ThreadTest s = new ThreadTest();
            System.out.println("T1 : " + s.isContainsInSet1("set1-99"));               
        }
    }
     
    private static class T2 extends Thread {
        public void run() {
            ThreadTest s = new ThreadTest();
            System.out.println("T2 : " + s.isContainsInSet2("set2-99"));               
        }
    }
     
    private static class T3 extends Thread {
        public void run() {
            ThreadTest s = new ThreadTest();
            System.out.println("T3 : " + s.isContainsInSet3("set3-99"));               
        }
    }
     
    private static class T4 extends Thread {
        public void run() {
            ThreadTest s = new ThreadTest();
            System.out.println("T4 : " + s.isContainsInSet4("set4-99"));               
        }
    }
     
    private static class T5 extends Thread {
        public void run() {
            ThreadTest s = new ThreadTest();
            System.out.println("T5 : " + s.isContainsInSet5("set5-99"));               
        }
    }
 
}

输出结果:

T1 : true
T0 : false
T0 : true
T1 : true
T2 : true
T2 : true
T3 : true
T5 : true
T4 : true
T3 : true
T4 : true
T5 : true

T0的结果时不时就为false。应该是非线程安全的。

抱歉!评论已关闭.