2017年2月28日 星期二

[ Java 常見問題 ] Java Synchronized list

Source From Here 
Question: 
I have a pre-populated array list. And I have multiple threads which will remove elements from the array list. Each thread calls the remove method below and removes one item from the list. Does the following code give me consistent behavior ? 
  1. ArrayList list = Collections.synchronizedList(new ArrayList());  
  2.   
  3. void remove(String item)  
  4. {  
  5.      do something; (doesn't work on the list)  
  6.      list.remove(item);  
  7. }  
How-To 
Check below sample code which doesn't do synchronization protection: 
  1. package demo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class MultiThreads {  
  7.     static class RThd implements Runnable{  
  8.         List     list = null;  
  9.         int             rc = 0;  
  10.           
  11.         public RThd(List list)  
  12.         {  
  13.             this.list = list;  
  14.         }  
  15.           
  16.         @Override  
  17.         public void run() {  
  18.             while(!list.isEmpty())  
  19.             {  
  20.                 System.out.printf("\t[%s] Remove %d\n", Thread.currentThread().getName(), list.remove(0));  
  21.                 rc++;  
  22.             }  
  23.         }  
  24.           
  25.     }  
  26.   
  27.     public static void main(String[] args) throws Exception{  
  28.         List list = new ArrayList();  
  29.         for(int i=0; i<100000; i++) list.add(i);  
  30.         List thdList = new ArrayList();  
  31.         ThreadGroup tg1 = new ThreadGroup("Group A");     
  32.         for(int i=0; i<10; i++)   
  33.         {  
  34.             RThd r = new RThd(list);  
  35.             thdList.add(r);  
  36.             new Thread(tg1, r).start();  
  37.         }  
  38.           
  39.         while(tg1.activeCount()>0)  
  40.         {  
  41.             Thread.sleep(500);            
  42.         }  
  43.         int rcc = 0;  
  44.         for(RThd r:thdList) rcc+=r.rc;  
  45.         System.out.printf("\t[Info] Done (%d)!\n", rcc);  
  46.     }  
  47. }  
When you execute it, you probably see the message what shows the removing action seems weird: 
...
[Thread-7] Remove null
[Thread-7] Remove null

[Thread-3] Remove 91578
[Thread-9] Remove 91577
[Thread-5] Remove 91576
[Thread-1] Remove 91575
[Thread-8] Remove 91685
[Thread-4] Remove 91644
[Thread-6] Remove 91643
[Thread-0] Remove 91642
[Thread-2] Remove 91641
[Info] Done (100113)!

You can resolve this issue by below code change which will make sure every thread to access the list with synchronization protection: 
  1. List list = new ArrayList();  
  2. list = Collections.synchronizedList(list);  
Just be careful if you are also iterating over the list, because in this case you will need to synchronize on it. From the Javadoc: 
It is imperative that the user manually synchronize on the returned list when iterating over it:

  1. List list = Collections.synchronizedList(new ArrayList());  
  2.     ...  
  3. synchronized (list) {  
  4.     Iterator i = list.iterator(); // Must be in synchronized block  
  5.     while (i.hasNext())  
  6.         foo(i.next());  
  7. }  
Or, you can use CopyOnWriteArrayList which is slower for writes but doesn't have this issue. 

Supplement 
ThreadGroup in Java

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...