Aynı anda "tam olarak" iki iş parçacığı nasıl başlatılır?


94

Konular aynı saniyede başlamalıdır. Anlıyorum, eğer bunu yaparsanız thread1.start(), bir sonraki yürütme işleminden önce birkaç milisaniye sürecektir thread2.start().

Mümkün mü yoksa imkansız mı?


2
Bölünmüş saniye, GHz hızlarında çok uzun bir süredir.
Nikolai Fetissov

32
Bu kadar yoğun bir şekilde olumsuz oy kullanmanıza gerek yok. Herkes iş parçacığı ile ilgili belirsizliği anlamıyor ve hepimiz bir yerden başlamalıyız.
Michael Petrotta

7
Olumsuz oyları anlamayın. İş parçacıkları arasında senkronizasyon çok yaygın bir gerekliliktir. Evet, java'da bunların tam olarak paralel olarak yürütülmesini sağlayamazsınız (bu, başka bir platformda çok geçerli bir gereksinim olabilir), ancak zaman zaman eylemlerini senkronize etmeniz çok yaygın bir durumdur. Bu yüzden jdk'nin bunu yapmak için dersleri vardır. Belki ifade doğru değildi, ama cehennem bunu bilseydi soruyu
sormazdı

Pekala, sanırım tüm öfkeni anlıyorum. Bana bir röportajda sorulan bir soruydu ... muhtemelen bir hileydi S. bu yüzden mümkün olup olmadığını sordum.
figaro

2
@javaguy - "hileli" bir soru değil. Daha ziyade, genel olarak çok iş parçacıklı programlamayı ne kadar iyi anladığınızı görmek için seçilen bir soru ...
Stephen C

Yanıtlar:


138

Konuları tam olarak aynı anda başlatmak için (en azından olabildiğince iyi), bir CyclicBarrier kullanabilirsiniz :

// We want to start just 2 threads at the same time, but let's control that 
// timing from the main thread. That's why we have 3 "parties" instead of 2.
final CyclicBarrier gate = new CyclicBarrier(3);

Thread t1 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};
Thread t2 = new Thread(){
    public void run(){
        gate.await();
        //do stuff    
    }};

t1.start();
t2.start();

// At this point, t1 and t2 are blocking on the gate. 
// Since we gave "3" as the argument, gate is not opened yet.
// Now if we block on the gate from the main thread, it will open
// and all threads will start to do stuff!

gate.await();
System.out.println("all threads started");

Bunun a olması gerekmez, CyclicBarrierbir CountDownLatchveya hatta bir kilit de kullanabilirsiniz .

Bu hala standart JVM'lerde tam olarak aynı anda başladıklarından emin olamaz , ancak oldukça yaklaşabilirsiniz. Oldukça yakınlaşmak, örneğin performans testleri yaptığınızda hala yararlıdır. Örneğin, bir veri yapısının verimini, kendisine çarpan farklı sayıda iş parçacığı ile ölçmeye çalışıyorsanız, mümkün olan en doğru sonucu elde etmek için bu tür bir yapı kullanmak istersiniz.

Diğer platformlarda, iş parçacığı başlatmak tam olarak çok geçerli bir gereksinim olabilir btw.


5
+1 iyi fikir ;-) Elbette iş parçacıklarının gerçek zamanlı olarak tam olarak aynı anda başlamasını sağlamaz (en azından tek çekirdekli bir yongada ve çok çekirdekli bir yongada bile garanti edilmez), ancak Daha iyisini yapmanın bir yolunu düşünemiyorum.
David Z

Bu, ortama özgü bekleme tutamaçlarına bağlanacak mı?
ChaosPandion

@ChaosPandion: Ayrıntılandırmak ister misiniz?
Noel Baba

@Santa - Örneğin Win32 API farklı ilkeler sunar. Yararlı bir tür, aradığınızda döndürülen manuel sıfırlama olaydır CreateEvent. msdn.microsoft.com/en-us/library/ms686364%28VS.85%29.aspx
ChaosPandion

1
@Zwei - Her neyse, Java gurusu olsaydım göndereceğim cevap buydu.
ChaosPandion

15

En azından tek çekirdekli bir bilgisayarda mümkün değil. Ama bunu neden istiyorsun? Tam olarak aynı saniyede iki iş parçacığı başlatabilseniz bile, bunlar farklı şekilde ilerleyecektir çünkü programlama sizin kontrolünüzde değildir.

Düzenleme: (Bazı yorumlara yanıt olarak) Birden çok iş parçacığının durumunu veya ilerlemesini senkronize etmek tamamen geçerli bir gerekliliktir ve CyclicBarrierharika bir araçtır. Aynı anda birden fazla iş parçacığı başlatmanın mümkün olup olmadığı sorusuna cevap verdim . CyclicBarrieriş parçacıklarının tam olarak istenen durumda olduklarında ilerlemelerini garanti eder , ancak oldukça yakın olsa da tam olarak aynı anda başlayacaklarını veya devam edeceklerini garanti etmez . Soruda senkronizasyon ihtiyaçlarından bahsedilmiyor.


1
Yine de oldukça yaklaşabilirsin. Her şey kullandığınız senkronizasyon tekniklerine ve tabii ki 1'den fazla cpu veya çekirdeğe sahip
ChaosPandion

Buradaki fikir şudur ki, bu yanlış bir yaklaşımdır ve gerçek zamanlı olmayan herhangi bir ortamda gerekli olmamalıdır, "oldukça yakın" olması değil.
Nikolai Fetissov

1
Öyle de Java konu zamanlama size milisaniye doğruluğunu vermez çünkü imkansız.
Stephen C

1
@Zwei - Boşta duran bir makinede muhtemelen çoğu zaman "çok yakın" olabilirsiniz. Ancak her zaman ihtiyacınız varsa, işletim sisteminde gerçek zamanlı desteği olan bir makinede C gibi bir dilde programlamanız gerekir. Ayrıca, iş parçacıklarınızı başlatmak istediğiniz "bölünmüş saniye" de JVM'nin tam bir GC çalıştırabileceğini de göz önünde bulundurun.
Stephen C

1
Bu tamamen geçerli bir senkronizasyon problemidir. İleti dizilerinin bazı verileri başlatması gerekir, doğru doğrulama olmadan kimsenin kritik bir bölgeye girmediğinden emin olun. Ve CyclicBerrier'in javas eşzamanlı paketine dahil olması, bunun önemli bir sorun olduğu anlamına geliyor.
Denis Tulskiy

14

Bunun için bir CountDownLatch kullanabilirsiniz. Lütfen aşağıda bir örnek bulun. T1 ve t2 başlatılsa da, bu iplikler ana iplik mandalı geri sayana kadar beklemeye devam eder. Gerekli geri sayım sayısı kurucuda belirtilmiştir. Geri sayım mandalı, ana iş parçacığının daha fazla ilerleyebilmesi için iş parçacıklarının yürütmeyi bitirmesini beklemek için de kullanılabilir (tersi durum). Bu sınıf Java 1.5'ten beri dahil edilmiştir.

import java.util.concurrent.CountDownLatch;


public class ThreadExample
{
    public static void main(String[] args) 
    {
        CountDownLatch latch = new CountDownLatch(1);
        MyThread t1 = new MyThread(latch);
        MyThread t2 = new MyThread(latch);
        new Thread(t1).start();
        new Thread(t2).start();
        //Do whatever you want
        latch.countDown();          //This will inform all the threads to start
        //Continue to do whatever
    }
}

class MyThread implements Runnable
{
    CountDownLatch latch;
    public MyThread(CountDownLatch latch) 
    {
        this.latch = latch;
    }
    @Override
    public void run() 
    {
        try 
        {
            latch.await();          //The thread keeps waiting till it is informed
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Do the actual thing
    }
}

Bu cevap, kod örneğinde daha az standart metinden faydalanabilir.
user2418306

6
  1. Anladığım kadarıyla, JVM bu şeyleri çoğunlukla işletim sistemine devrediyor. Dolayısıyla cevap işletim sistemine özgü olacaktır.
  2. Tek işlemcili makinelerde açıkça imkansızdır.
  3. Çok işlemcili bir makineye göre daha karmaşıktır. Eşzamanlılığın Göreliliği'ne göre , "iki olayın aynı anda meydana gelip gelmediğini mutlak anlamda söylemek imkansızdır, bu olaylar uzayda ayrıştırılırsa." İşlemcileriniz ne kadar yakın olursa olsun, boşlukta ayrılırlar.
    1. Göreceli eşzamanlılığı kabul edebiliyorsanız, diğer yanıtlarda tartışılan teknikleri kullanarak onu simüle etmek muhtemelen daha kolaydır.

1
… Ve eşzamanlı bir başlangıcı varsaysak bile, her iş parçacığının kendi zaman çizelgesi vardır, hepsi eşzamanlıdır , ancak zorunlu olarak paralel değildir, bu nedenle herhangi biri iş parçacıklarının eşzamanlılığı hakkında varsaydığı her ne olursa olsun (hangisi olursa olsun) bir sonraki nanosaniye içinde geçersiz olabilir (olacaktır). zaman çizelgesi)…
Holger
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.