2013-03-03 88 views
0

我想用2個不同的線程交替打印奇數和偶數。我能夠實現它使用等待,通知和同步塊,但現在我想評估,如果我們可以實現它,而無需使用等待,通知和同步。java:使用2個線程打印奇數偶數

以下是代碼我有,但它不工作:

public class OddEvenUsingAtomic { 

AtomicInteger nm = new AtomicInteger(0); 
AtomicBoolean chk = new AtomicBoolean(true); 

public static void main(String args[]) { 
    final OddEvenUsingAtomic pc = new OddEvenUsingAtomic(); 

    new Thread(new Runnable() { 

     @Override 
     public void run() { 
      while (true) { 

       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 

       if (pc.chk.compareAndSet(true, false)) { 

        System.out.println("Odd: " + pc.nm.incrementAndGet()); 
       } 
      } 

     } 

    }).start(); 

    new Thread(new Runnable() { 

     @Override 
     public void run() { 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      while (true) { 
       if (pc.chk.compareAndSet(false, true)) { 

        System.out.println("Even: " + pc.nm.incrementAndGet()); 
       } 
      } 

     } 

    }).start(); 
} 

}

任何想法?

我創建布魯諾建議後另一個版本,這似乎是更好的工作:

import java.util.concurrent.atomic.AtomicBoolean; 
import java.util.concurrent.atomic.AtomicInteger; 

public class OddEvenUsingAtomic { 

    AtomicInteger nm = new AtomicInteger(0); 
    AtomicBoolean chk = new AtomicBoolean(true); 

    public static void main(String args[]) { 
     final OddEvenUsingAtomic pc = new OddEvenUsingAtomic(); 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       while (true) { 

        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 

        if (pc.chk.get() == Boolean.TRUE) { 

         System.out.println("Odd: " + pc.nm.incrementAndGet()); 
         pc.chk.compareAndSet(true, false); 
        } 
       } 

      } 

     }).start(); 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
       while (true) { 
        if (pc.chk.get() == Boolean.FALSE) { 

         System.out.println("Even: " + pc.nm.incrementAndGet()); 
         pc.chk.compareAndSet(false, true); 
        } 
       } 

      } 

     }).start(); 
    } 
} 
+1

你的意思是「它不工作」是什麼意思?你得到了什麼結果?您是否嘗試在調試器中運行代碼,或者啓用了一些額外的日誌記錄? – 2013-03-03 04:26:52

+0

使用上面的代碼我想要一個線程打印只偶數和其他線程打印只有奇數。我想用Atomic Integer來實現它,但是它沒有發生。線程正在混合奇數偶數值。 – Lokesh 2013-03-03 04:29:25

+1

*「線程正在混合奇數偶數值。」* - 請描述發生了什麼**清楚**。 「混合」並不是一個明確的描述。 – 2013-03-03 04:35:46

回答

3

的代碼不正確同步,這就是問題所在。

下面的執行順序是允許在你的代碼:

  1. 第一線看到chk == true,將其設置爲false並進入if塊。
  2. 第二個線程看到chk == false,將其設置爲true並輸入if塊。

現在,你有兩個自己的if塊中2個線程,準備:

  1. incrementAndGet()
  2. 打印。

因此,你完全無法控制將要發生的事情。

  • 您可以讓任何線程調用incrementAndGet(),因此您可以讓線程「奇數」打印,首先是奇數,後來是偶數。
  • 你可以讓第一個線程打印數字,循環,看到條件再次滿足(因爲第二個線程已經設置了chktrue再次打印,所有這些在第二個線程之前有機會打印)。

正如你所看到的,達到你想要的結果,你必須具備以下操作自動完成的:

  • compareAndSet()布爾
  • incrementAndGet()
  • 打印它

如果3個操作不是原子的,那麼你可以讓這些線程被安排在任何位置運行操作sible命令,你無法控制輸出。實現這一目標的最簡單方法是使用synchronized塊:

public static void main(final String... args) { 
    final Object o = new Object(); 
    // ... thread 1 ... 
    synchronized(o) { 
     if (boolean is in the expected state) { change boolean, get number, increment, print } 
    } 
    // ... thread 2 ... 
    synchronized(o) { 
     if (boolean is in the expected state) { change boolean, get number, increment, print } 
    } 
} 
+0

完美,這SHLD工作...我已經通過代碼編輯似乎是工作。只有一件事情是在增量之後改變布爾值。你同意嗎?另外,如果我們將增量布爾值更改爲後,那麼我們是否需要同步?我不這麼認爲 – Lokesh 2013-03-03 04:53:03

+0

你的編輯讓我的答案對那些閱讀新版本問題的人完全無效。我真的認爲你應該回復你的編輯,留下你的第一個錯誤版本,並在問題的最後添加你的新的正確版本,最好是在你明確表明你添加了作爲編輯的東西之後,你有一些答案。在那之後,我會評論你的新輸入和你的新版本,以及它與我的回答之間的關係。這裏有一些禮儀。 – 2013-03-03 04:55:34

+0

在第一個版本下面添加了新版本,並對先前的錯誤表示歉意。我想知道我們是否真的需要同步。 – Lokesh 2013-03-03 05:02:02

3

這裏有兩個線程打印的賠率,並沒有等待找齊,通知或同步的(至少不是在代碼中可以看到):

import java.util.concurrent.*; 

public class ThreadSignaling { 
    public static void main(String[] args) { 
     BlockingQueue<Integer> evens = new LinkedBlockingQueue<>(); 
     BlockingQueue<Integer> odds = new LinkedBlockingQueue<>(); 
     ExecutorService executorService = Executors.newFixedThreadPool(2); 
     executorService.submit(() -> takeAndOfferNext(evens, odds)); 
     executorService.submit(() -> takeAndOfferNext(odds, evens)); 
     evens.offer(0); 
    } 

    private static void takeAndOfferNext(BlockingQueue<Integer> takeFrom, 
             BlockingQueue<Integer> offerTo) { 
     while (true) { 
      try { 
       int i = takeFrom.take(); 
       System.out.println(i); 
       offerTo.offer(i + 1); 
      } catch (InterruptedException e) { 
       throw new IllegalStateException("Unexpected interrupt", e); 
      } 
     } 
    } 
} 
+1

哦,我只是喜歡Java 8的lambdas ... – 2013-03-03 05:14:04

+0

驅動器downvoter?任何特定的原因? – 2013-03-03 05:18:12

0
class MultiThreading { 

    Integer counter = 0; 
    Thread even; 
    Thread odd; 
    boolean flagEven = true; 
    boolean flagOdd; 

    class ThreadEven implements Runnable { 
     @Override 
     public void run() { 
      try { 
       while (counter < 100) { 
        if (flagEven) { 
         System.out.println(counter); 
         counter++; 
         flagEven = false; 
         flagOdd = true; 
        } 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    class ThreadOdd implements Runnable { 
     @Override 
     public void run() { 
      try { 
       synchronized (even) { 
        while (counter < 100) { 
         if (flagOdd) { 
          System.out.println(counter); 
          counter++; 
          flagOdd = false; 
          flagEven = true; 
         } 
        } 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public void start() { 
     even = new Thread(new ThreadEven()); 
     odd = new Thread(new ThreadOdd()); 
     even.start(); 
     odd.start(); 
    } 

} 

}

呼叫的主要方法

new MultiThreading().start();