在多线程环境中,如果是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。应该是非线程安全的。