2015-09-02 64 views
8

में दो महत्वपूर्ण वर्गों पर अमल मैं कोड की निम्न प्रकार है:तुल्यकालन: धागे उसी क्रम

synchronized block1 { 
    //only one thread in the block 
} 

{lot of code where synchronization not necessary} 

synchronized block2 { 
    //only one thread in the block. 
    //All the threads that executed block1 before this thread should have already executed this block. 
} 

प्रत्येक धागा पहला यह है कि एक ही क्रम में block1, गैर सिंक्रनाइज़ ब्लॉक, और block2 निष्पादित करता है।

यदि थ्रेड टी 1 थ्रेड टी 2 से पहले ब्लॉक 1 निष्पादित करता है, तो टी 1 को टी 2 से पहले ब्लॉक 2 निष्पादित करना चाहिए। दो से अधिक धागे हैं।

जावा में इसे प्राप्त करने का कोई तरीका है?

+0

मुझे लगता है कि आप ब्लॉक 1 के अंदर 'block2() 'को कॉल नहीं कर सकते? –

+0

@ निकोलसरोबिन्सन कोई कॉल नहीं। सभी कोड दिए गए क्रम में निष्पादित किया गया है। –

+0

क्या यह एक विधि में है? सिंक्रनाइज़ (यह) {...} 'का उपयोग करना या वे अलग-अलग तरीके हैं? –

उत्तर

3

मैं समझता हूँ के रूप में महत्वपूर्ण धारा # 2 के रूप में महत्वपूर्ण अनुभाग # उसी क्रम में निष्पादित किया जाना चाहिए धागा T1 धागा टी 2 से पहले block1 कार्यान्वित 1

है, तो टी 1 से पहले block2 पर अमल करना चाहिए टी 2। दो से अधिक धागे हैं।

फिर निष्पादन के आदेश को सुनिश्चित करने के लिए एक कतार का उपयोग किया जा सकता है।

private Object lock = new Object(); 
private Queue<Thread> threadQueue = new ArrayDeque<>(); 

// https://stackoverflow.com/questions/32353283/synchronization-threads-execute-two-critical-sections-in-same-order 
public void executeCriticalSectionsInOrder() throws InterruptedException { 
    // Critical Section #1 
    synchronized (lock){ 
     // synchronized code #1 

     // Add self to queue 
     threadQueue.add(Thread.currentThread()); 
    } 

    // {lot of code where synchronization not necessary} 

    // Critical Section #2 
    synchronized (lock) { 
     //All the threads that executed block1 before this thread should have already executed this block. 
     // Wait turn 
     Thread t = threadQueue.element(); // Do not remove until it is self 
     while (t != Thread.currentThread()) { 
      lock.wait(); 
      // After sleep try again 
      t = threadQueue.element(); 
     } 
     // Verified own turn. Update status 
     threadQueue.remove(); 

     // synchronized code #2 

     lock.notifyAll(); // Awake any waiting thread after exiting section. 
    } 

एक धागा मर जाता है हालांकि हैं/कतार से ही हटाने, उसके बाद निम्न सूत्र के बिना बाहर निकलता है indefinetely अवरुद्ध हो जाएगा। शायद हाउसकीपिंग करने के लिए आखिरकार ब्लॉक जोड़ें?

नोट: Nicholas Robinson's answer में एक कतार के बजाय एक स्थिति आदेश सुझाया गया था, जो थोड़ा अधिक कुशल लगता है।

-2

आपको Lock का उपयोग करने में सक्षम होना चाहिए जो आप block1 पर कॉल करने से पहले लेते हैं और block2 पर कॉल करने के बाद रिलीज़ करते हैं।

static Lock lock = new ReentrantLock(); 
Random random = new Random(); 

public void block1() throws InterruptedException { 
    System.out.println("Enter block 1"); 
    Thread.sleep(random.nextInt(500)); 
    System.out.println("Leave block 1"); 
} 

public void block2() throws InterruptedException { 
    System.out.println("Enter block 2"); 
    Thread.sleep(random.nextInt(500)); 
    System.out.println("Leave block 2"); 
} 

private class BlockTester implements Runnable { 

    long start = System.currentTimeMillis(); 

    @Override 
    public void run() { 
     while (System.currentTimeMillis() < start + 10000) { 
      lock.lock(); 
      try { 
       System.out.println("Thread: " + Thread.currentThread().getName()); 
       block1(); 
       block2(); 
      } catch (InterruptedException ex) { 
       System.out.println("Interrupted"); 
      } finally { 
       lock.unlock(); 
      } 
     } 
    } 
} 

public void test() throws InterruptedException { 
    Thread[] blockTesters = { 
     new Thread(new BlockTester()), 
     new Thread(new BlockTester()), 
     new Thread(new BlockTester()), 
     new Thread(new BlockTester()), 
     new Thread(new BlockTester()) 
    }; 
    for (Thread t : blockTesters) { 
     t.start(); 
    } 
    for (Thread t : blockTesters) { 
     t.join(); 
    } 

} 
+0

आप अन्य के बाद ब्लॉक 1() और block2() को कॉल कर रहे हैं, क्या हम उन्हें एक विधि में नहीं रख सकते हैं? –

+0

यह न देखें कि यह ओपी को कैसे संतुष्ट करता है - वह ब्लॉक 1 और अन्य unsynced कोड के माध्यम से जाने के लिए कई धागे चाहता है - वह क्या नहीं करता है कि वह एक थ्रेड है जो दूसरे से आगे निकलता है और पहले 2 को ब्लॉक करता है। विशेष रूप से वह ब्लॉक 2 पर एक थ्रेड को निलंबित करना चाहता है अगर एक और धागा जो ब्लॉक 1 को पारित करने से पहले अभी तक नहीं चला है। – Elemental

+0

आप इसे कैसे प्रबंधित कर रहे हैं: '{बहुत सारे कोड जहां सिंक्रनाइज़ेशन आवश्यक नहीं है}' –

3

यह मूल रूप से एक कतार बनाता है कि धागे उनकी संख्या तक आने तक प्रतीक्षा करेंगे। [अपडेट]

private AtomicInteger place = new AtomicInteger(0); 
private AtomicInteger currentPlaceInQueue = new AtomicInteger(0); 
private ReentrantLock lock = new ReentrantLock(); 
private Condition notNext = lock.newCondition(); 

public void method() { 

    ThreadLocal position = new ThreadLocal(); 

    synchronized(this) { 
     //Your code 
     position.set(place.getAndIncrement()); 
    } 

    // More code 

    lock.lock(); 
    while ((int) currentPlaceInQueue.get() != position.get()) { 
     notNext.await(); 
    } 
    // More code 
    lock.unlock(); 
    currentPlaceInQueue.getAndIncrement(); 
    notNext.notifyAll(); 
} 
+0

बस जांचें, थ्रेडलोकल परिभाषा को ऑब्जेक्ट वैरिएबल होना पड़ सकता है। –

+0

चालाक समाधान – marthursson

+0

मुझे नहीं पता कि क्यों 'थ्रेडलोकल' की आवश्यकता है - यह कक्षा के लिए एक विधि के लिए scoped है। –

0

synchronized आपके उदाहरण में ब्लॉक लाल हेरिंग हैं। आपकी समस्या यह है कि आपके पास एन थ्रेड हैं, और आपके पास कोड के दो ब्लॉक हैं, और आप यह सुनिश्चित करना चाहते हैं कि कोई भी थ्रेड दूसरे ब्लॉक में प्रवेश न करे जब तक कि उनमें से सभी ने पहला ब्लॉक समाप्त नहीं किया हो।

इसके लिए आप CyclicBarrier का उपयोग करते हैं। http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html

संबंधित मुद्दे