İş Parçacığı Güvenliği ve Yan Etkiler
Paylaşılan değiştirilebilir durumdan kaçının
İş Parçacığı Güvenliği ve Yan Etkiler, CoddyKit'te ücretsiz bir Java Academy dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Java Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Java Academy kursu toplamda 4 dersten oluşur.
parallel Eşzamanlı Erişim Demektir
Bir paralel stream'de birden çok iş parçacığı lambda ifadelerinizi aynı anda çalıştırır. Dokundukları herhangi bir paylaşılan değiştirilebilir durum yarış durumuna dönüşür.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int safe = IntStream.rangeClosed(1, 1000).parallel().sum();
System.out.println(safe);
}
}Tehlike: Paylaşılan Bir Değişkeni Değiştirme
Birçok iş parçacığının eriştiği sıradan bir int sayacı, güncellemeleri kaybeder. forEach içinde hiçbir zaman paylaşılan değiştirilebilir durumda biriktirme yapmayın.
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
AtomicInteger counter = new AtomicInteger();
IntStream.rangeClosed(1, 1000).parallel()
.forEach(n -> counter.incrementAndGet());
System.out.println(counter.get());
}
}Sıradan Koleksiyonlar Neden Bozulur
Paralel bir forEach içinden iş parçacığı güvenli olmayan bir ArrayList'e ekleme yapmak, koleksiyonu bozabilir veya öğelerin kaybolmasına neden olabilir. Çözüm, hiç paylaşmamak ve değiştirmemektir.
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
List<Integer> result = IntStream.rangeClosed(1, 10).parallel()
.boxed()
.collect(Collectors.toList());
System.out.println(result.size());
}
}Doğru Araç: collect
Yan etkili forEach yerine collect kullanın. Toplayıcı çerçevesi, her iş parçacığı için kısmi kapsayıcıları güvenli biçimde biriktirir ve bunları birleştirir.
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
List<Integer> squares = IntStream.rangeClosed(1, 6).parallel()
.map(n -> n * n)
.boxed()
.collect(Collectors.toList());
System.out.println(squares);
}
}Doğru Araç: reduce
İşlem birleşme özelliğine sahip ve durumsuz olduğunda reduce doğası gereği iş parçacığı güvenlidir; çünkü sonuçları paylaşılan bir değişiklik olmadan birleştirir.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int sum = IntStream.rangeClosed(1, 1000).parallel()
.reduce(0, Integer::sum);
System.out.println(sum);
}
}Durumsuz Lambda İfadeleri
Akışlardaki lambda ifadeleri durumsuz olmalıdır: sonuçları dışarıdaki değiştirilebilir değişkenlere veya önceki öğelere değil, yalnızca girdiye bağlı olmalıdır.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long count = IntStream.rangeClosed(1, 1000).parallel()
.filter(n -> n % 2 == 0)
.count();
System.out.println(count);
}
}Kurtarıcı Olarak Atomik Türler
Bir sayacı gerçekten paylaşmanız gerekiyorsa AtomicLong gibi atomik sınıflar kullanın. Bunlar güncellemeleri doğru şekilde sıraya koyar ancak çekişme ekler.
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
AtomicLong sum = new AtomicLong();
IntStream.rangeClosed(1, 1000).parallel()
.forEach(sum::addAndGet);
System.out.println(sum.get());
}
}Eşzamanlı Koleksiyonlar
İş parçacıkları arasında paylaşılan bir map gerektiğinde ConcurrentHashMap güvenlidir. Yine de mümkün olduğunda Collectors.groupingByConcurrent kullanmayı tercih edin.
import java.util.Map;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> words = List.of("a", "bb", "cc", "ddd");
Map<Integer, List<String>> byLen = words.parallelStream()
.collect(Collectors.groupingByConcurrent(String::length));
System.out.println(byLen);
}
}Sıraya Bağımlı Mantıktan Kaçının
Paralel lambda ifadeleri içinde karşılaşma sırasına güvenmeyin. Sıralı işlem varsayan işlemler, paralel çalışmada yanlış sonuçlar üretir.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int sum = IntStream.rangeClosed(1, 100).parallel()
.map(n -> n * 2)
.sum();
System.out.println(sum);
}
}Saf İşlevler Güvenle Paralelleştirilebilir
Temel kural şudur: saf, durumsuz ve müdahale etmeyen işlemler yazın. Böylece bir stream, aynı doğru sonuçları vererek sıralı veya paralel çalışabilir.
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> in = List.of("red", "green", "blue");
String out = in.parallelStream()
.map(String::toUpperCase)
.sorted()
.collect(Collectors.joining(","));
System.out.println(out);
}
}Müdahale Etmeme
Bir stream üzerinde çalışırken kaynak koleksiyonu değiştirmeyin. Bu, sıralı veya paralel çalışmada ConcurrentModificationException ya da tanımsız davranışa neden olur.
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<Integer> src = List.of(1, 2, 3, 4);
List<Integer> doubled = src.parallelStream()
.map(n -> n * 2)
.collect(Collectors.toList());
System.out.println(doubled);
}
}Hızlı Kontrol
Paralel bir stream'den sonuçları biriktirmek için önerilen yöntem nedir?
Özet
Paralel stream'lerin doğruluğunu korudunuz:
- Paralel lambda ifadelerindeki paylaşılan değiştirilebilir durum, yarışlara neden olur.
- Yan etkili
forEachyerinecollectvereducekullanmayı tercih edin. - Lambda ifadelerini durumsuz, saf ve müdahale etmeyen biçimde tutun.
- Paylaşmanız kaçınılmazsa atomik türleri veya eşzamanlı koleksiyonları kullanın; ancak bu son çare olmalıdır.
Sıkça Sorulan Sorular
“İş Parçacığı Güvenliği ve Yan Etkiler” dersi ücretsiz mi?
Evet — “İş Parçacığı Güvenliği ve Yan Etkiler” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Java Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Java Academy kursu toplamda 4 dersten oluşur.
“İş Parçacığı Güvenliği ve Yan Etkiler” dersinde ne öğreneceğim?
Paylaşılan değiştirilebilir durumdan kaçının Java Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Java Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Java Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.
“İş Parçacığı Güvenliği ve Yan Etkiler” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Java Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Java Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Paralel Akışlar Oluşturma
- Paralellik Ne Zaman Yararlıdır
- İş Parçacığı Güvenliği ve Yan Etkiler
- Yaygın Tuzaklar