2017年3月6日 星期一

集合、ThreadLocal (Thread 五)

※集合

System.out.println("synchronized list");
List<Integer> l = new ArrayList<>();
synchronized (l) {
    l.add(1);
    l.add(2);
    l.add(3);
}
for (Integer i : l) {
    System.out.println(i);
}
    
System.out.println();
System.out.println("synchronizedCollection");
Collection<String> c = Collections.synchronizedCollection(new ArrayList<>());
c.add("A");
c.add("B");
c.add("C");
synchronized (c) {
    for (String s : c) {
        System.out.println(s);
    }
}
    
System.out.println();
System.out.println("synchronizedList");
List<String> list = Collections.synchronizedList(new ArrayList<>());
list.add("D");
list.add("E");
list.add("F");
    
synchronized (list) {
    for (String s : list) {
        System.out.println(s);
    }
}
    
System.out.println();
System.out.println("synchronizedSet");
Set<String> set = Collections.synchronizedSet(new HashSet<>());
set.add("G");
set.add("H");
set.add("G");
synchronized (set) {
    for (String s : set) {
        System.out.println(s);
    }
}
    
System.out.println();
System.out.println("synchronizedMap");
Map<Integer, String> map = Collections.synchronizedMap(new HashMap<>());
map.put(0, "A");
map.put(1, "B");
map.put(2, "C");
for (int i = 0; i < map.size(); i++) {
    System.out.println(map.get(i));
}

※這些是 java 1.5 之前的寫法,for 迴圈有用 synchronized ,是因為使用到 Iterator ,它並不是 Thread-safe,而 for each 會用到 Iterator 物件,但最原始的 for 迴圈不會用到



※ java 1.5 集合

System.out.println("CopyOnWriteArrayList");
List<String> list = new CopyOnWriteArrayList<>();
list.add("D");
list.add("E");
list.add("F");
for (String s : list) {
    System.out.println(s);
}
    
System.out.println();
System.out.println("CopyOnWriteArraySet");
Set<String> set = new CopyOnWriteArraySet<>();
set.add("G");
set.add("H");
set.add("G");
for (String s : set) {
    System.out.println(s);
}
    
System.out.println();
System.out.println("ConcurrentHashMap");
Map<Integer, String> map = new ConcurrentHashMap<>();
map.put(0, "A");
map.put(1, "B");
map.put(2, "C");
for (int i = 0; i < map.size(); i++) {
    System.out.println(map.get(i));
}

※java 1.5 新增了 java.util.concurrent 這個套件



※ThreadLocal

ThreadLocal 是 Thread 變數,在寫 Thread-safe 是很困難的,要讓 Thread 共用,又要同步,又有效能的問題,還要小心 Dead Lock,所以有人想到不要共用了,直接創造 Thread 的複本,在 java 1.2 就產生了 ThreadLocal 類別了,但此方法會需要較多的記憶體


public class ThreadTest extends Thread {
    private static int number;
    
    public int getNumber() {
        number = number + 1;
        return number;
    }
    
    // private static ThreadLocal<Integer> number = new ThreadLocal<Integer>() {
    // @Override
    // protected Integer initialValue() {
    // return 0;
    // }
    // };
    
    // public int getNumber() {
    // number.set(number.get() + 1);
    // return number.get();
    // }
    
    @Override
    public void run() {
        for (int i = 1; i <= 3; i++) {
            System.out.println(Thread.currentThread().getName() + "=" + getNumber());
        }
    }
    
    public static void main(String... a) {
        ThreadTest t1 = new ThreadTest();
        ThreadTest t2 = new ThreadTest();
        ThreadTest t3 = new ThreadTest();
    
        t1.start();
        t2.start();
        t3.start();
    }
}

※結果:
Thread-0=1
Thread-0=4
Thread-0=5
Thread-1=3
Thread-1=6
Thread-1=7
Thread-2=2
Thread-2=8
Thread-2=9

可以看得出來 Thread 之間被影響了,應該三個 Thread 都是 123 才是正確的


※打開註解並註解原來的 number 和 getNumber(),結果如下:
Thread-0=1
Thread-0=2
Thread-0=3
Thread-2=1
Thread-2=2
Thread-2=3
Thread-1=1
Thread-1=2
Thread-1=3


沒有留言:

張貼留言