2016-03-20 12 views
1

Java iş parçacıkları ile dalga geçiyorum ve birkaç iş parçacığı oluşturur ve bunları çalıştırır bu küçük programı yazdım. Her iş parçacığında bir değer birden çok kez artırılır. ThreadLocal sınıfını kullandım, böylece kaynaklar için bir çekişme yok.Java eşzamanlılığı: garip çıktı

Kaynak: çıktı zaman bunun en olduğunu

class MyValueHolder { 

    public static ThreadLocal<Integer> value = new ThreadLocal<Integer>() 
    { 
     protected Integer initialValue() { 
      return 0; 
     } 
    }; 

    public static void increment() { 
     value.set(value.get() + 1); 
    } 

    public static Integer get() { 
     return value.get(); 
    } 
} 

class MyTask implements Runnable { 

    public static int counter; 

    public MyTask() { 
     counter++; 
    } 

    public void run() { 

     for(int i = 0; i < 100; i++) { 
      MyValueHolder.increment(); 
     } 
     System.out.println("MyTask " + counter + ", Value " + MyValueHolder.get()); 
    } 
} 

public class Main { 

    public static void main(String[] args) { 

     ExecutorService es = Executors.newCachedThreadPool(); 

     for(int i = 0; i < 5; i++) { 

      es.execute(new MyTask()); 
     } 

     es.shutdownNow(); 
    } 
} 

tamamlanmasından sonra:

MyTask 5, Value 100 
MyTask 5, Value 100 
MyTask 5, Value 100 
MyTask 5, Value 100 
MyTask 5, Value 100 

Hangi görmeyi beklediğiniz budur.

MyTask 2, Value 100 
MyTask 4, Value 200 
MyTask 5, Value 300 
MyTask 5, Value 100 
MyTask 5, Value 100 

Şimdi bu kafa karıştırıcı:

Ancak, bazen böyle bir şey olsun. Her bir görev kesinlikle aynı şeyi yapsa bile değerler neden farklılık gösteriyor?

+0

Dişlerin çalıştığı sıra **, başlatıldıkları sırayla garanti edilmez. Konularınızın belirli bir sırada çalışması gerekiyorsa, 'wait' /' notify' veya ['CountDownLatch'] kullanın (https://docs.oracle.com/javase/7/docs/api/java/util/ eşzamanlı/CountDownLatch.html). – Majora320

cevap

5

CachedThreadPoolExecutor, Runnable tüm Runnable s eklemeden önce iş parçacıkları yeniden iş parçacığı yeniden kullanır. Bu olursa, bu iş parçacığının ThreadLocal da yeniden kullanılır.

0

iş parçacığı bir çıkış alırken çalışmaya devam edecek bitirdikten sonra bitirmesini bekler isAlive();

1

ile ilgili bilgiler Yukarıda belirtildiği gibi ThreadLocal yeniden kullanılıyor.

Sayaç için, AtomicInteger yerine kullanın ve bir başlangıç ​​değeri ayarlayın. sayacı ++ bir atomik işlem değildir, iki işlemidir ve iş parçacığı güvenli değildir.

+0

"Sayaç" şu anda sorunlu değil, çünkü değer yapıcı içinde artırılıyor - ve yapıcı sadece ana yöntemden çağrılıyor. –

+0

Üzgünüm, açıkça haklısınız, sayaç, tüm kurucular çağrılmadan önce iş parçacığının çalışma yöntemi bittiğinden yanlış numaralar yazdırıyor. – LiozM

İlgili konular