2015-11-25 28 views
8

Java 8 paralel akışında bir ThreadLocal değerini nasıl kopyalayabilirim anlamaya çalışıyorum.Java 8 paralel akışı ve ThreadLocal

bu düşünün Yani eğer:

Main Thread: MAIN 
Parallel Consumer - 5: MAIN 
Parallel Consumer - 4: MAIN 
Parallel Consumer - 7: empty 
Parallel Consumer - 3: empty 
Parallel Consumer - 1: empty 
Parallel Consumer - 6: empty 
Parallel Consumer - 2: empty 
Parallel Consumer - 0: MAIN 

verir

public class ThreadLocalTest { 

     public static void main(String[] args) { 
      ThreadContext.set("MAIN"); 
      System.out.printf("Main Thread: %s\n", ThreadContext.get()); 

      IntStream.range(0,8).boxed().parallel().forEach(n -> { 
       System.out.printf("Parallel Consumer - %d: %s\n", n, ThreadContext.get()); 
      }); 
     } 

     private static class ThreadContext { 
      private static ThreadLocal<String> val = ThreadLocal.withInitial(() -> "empty"); 

      public ThreadContext() { 
      } 

      public static String get() { 
       return val.get(); 
      } 

      public static void set(String x) { 
       ThreadContext.val.set(x); 
      } 
     } 
    } 

beni her paralel için kökenli iş parçacığı içine ana() yönteminden ThreadLocal klonlamak için bir yol var mı yürütme?

Böyle yani benim sonucu olduğunu: yerine bir ilk

Main Thread: MAIN 
Parallel Consumer - 5: MAIN 
Parallel Consumer - 4: MAIN 
Parallel Consumer - 7: MAIN 
Parallel Consumer - 3: MAIN 
Parallel Consumer - 1: MAIN 
Parallel Consumer - 6: MAIN 
Parallel Consumer - 2: MAIN 
Parallel Consumer - 0: MAIN 

?

+3

Bunu beklemezdim. Ama neden bu "ThreadLocal" ilk etapta, sadece ana metodunuzda yaratılmış ve daha sonra açıkça lambdaya aktarıldı? –

+4

Akışları geçmeye mi çalışıyorsunuz? Kötü olacağını duydum. – zapl

cevap

7

As Louis has stated in the comments , senin örneğin çok iyi lambda ifadesi tam kullanım durumları ne senin örnekten belli değil

public static void main(String[] args) { 
    String value = "MAIN"; 
    System.out.printf("Main Thread: %s\n", value); 

    IntStream.range(0,8).boxed().parallel().forEach(n -> { 
     System.out.printf("Parallel Consumer - %d: %s\n", n, value); 
    }); 
} 

yerel değişkenin değerini yakalayan indirgenebilir.

Eğer ipler ana parçacığından başladı olacak tam olarak ne biliyorsanız, alt iş parçacığı için ana akıştan değerlerin mirasını sağlamak için Bu sınıf ThreadLocal uzanan bir InheritableThreadLocal

kullanmayı düşünebilirsiniz : Bir çocuk iş parçacığı oluşturulduğunda, alt öğesinin, üst öğenin değerleri olduğu tüm kalıtımsal iş parçacığı yerel değişkenleri için başlangıç ​​değerleri alınır. Bir InheritableThreadLocal olarak val ilan Senin durumunda

, ForkJoinPool#commonPool() içinde parallel() için oluşturulan Thread örnekleri tembel oluşturulduğundan, hepsi main yöntemi (ve iplik) değer set devralan olacaktır. Bir şekilde kullanılırsa

Bu durumda olmazdı commonPool (veya parallel terminali operasyonu çağrısında ne varsa pool) kökeni dizisindeki InhertiableThreadLocal değerini ayarlamadan önce.

+0

Evet, örneğim kullanım durumu hakkında çok fazla bilgi vermiyordu. Gerçek kullanım durumu, başka bir kodla birlikte (paralel() tüketicinin dışında) ve ThreadLocal bir Servlet filtresinde doldurulur ve daha sonra bir Spring MVC kontrolöründe kullanılır ve bazı zamanlarda kart boyunca çeşitli çalıştırılabilir uygulamalar için klonlanır (servis çağrıları, vb. Yani ThreadContext.get (bir şey) olan yolda çeşitli aramalar olacak. InheritableThreadLocal açıklayan için teşekkürler, ben bir deneyecek! –