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