【问题标题】:Java: How to print odd and even numbers from 2 separate threads using Executor frameworkJava:如何使用 Executor 框架从 2 个单独的线程中打印奇数和偶数
【发布时间】:2012-07-09 20:17:27
【问题描述】:

我想要一个在不同线程中打印奇数和偶数的算法。输出应该是顺序的1,2,3.4 ,.....这里可以使用Executor框架。我见过 related question on SO 但那是在 C 中。我想要这里的 Java 实现。

【问题讨论】:

  • 如果你必须像“结果应该是连续的”,那你就错了。 “线程”和“顺序”不能很好地结合在一起;线程在他们喜欢的时候运行得差不多了。考虑一下能够同时做两件事的代价——你放弃了对它们完成的确切以什么顺序的控制。如果你想让东西以特定的顺序运行,你必须做一些同步(阅读:使线程阻塞!)只是为了免费获得顺序处理给你的东西。

标签: java multithreading algorithm java.util.concurrent


【解决方案1】:

它是 jasons 的修改版:

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class Test {

    public static void main(String[] args){
    final int max = 100;
    final AtomicInteger i = new AtomicInteger(0);
    Executor dd = Executors.newFixedThreadPool(2);

    final Object lock = new Object();

    dd.execute(new Runnable() {
        @Override
        public void run() {
            while (i.get() < max) {
                if (i.get() % 2 == 0) {
                    System.out.print(" " + i.getAndAdd(1));

                    synchronized(lock){
                        lock.notify();
                    }
                }else{
                    synchronized(lock){
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    });
    dd.execute(new Runnable() {
        @Override
        public void run() {
            while (i.get() < max) {
                if (i.get() % 2 != 0) {
                    System.out.print(" " + i.getAndAdd(1));

                    synchronized(lock){
                        lock.notify();
                    }
                }else{
                    synchronized(lock){
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    });
    do {
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    } while (i.get() != max);
    System.out.println("\nDone");
}
}

免责声明:它不是最好的解决方案,当然也不是最快的,但它会产生正确的输出。

这是输出:

 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
Done

【讨论】:

    【解决方案2】:

    您的问题有点令人困惑,因为您似乎希望按顺序输出。

    在这种情况下使用线程是没有意义的,因为它们会不断地相互协调以确定轮到谁输出它们的当前数字。

    如果您不关心排序(例如,您可能会得到 1、2、3、5、4、6、8.7...),那么它可能是有意义的。

    public class Test
    {
        private static final int NOT_APPLICABLE = 1;
    
        private final ExecutorService executor;
    
        public Test()
        {
            BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2);
    
            executor = new ThreadPoolExecutor(2, 2, NOT_APPLICABLE, TimeUnit.SECONDS, queue);
        }
    
        public void submitTask(Runnable task)
        {
            executor.submit(task);
        }
    
        private static class Counter implements Runnable
        {
            private int counter;
    
            public Counter(int start)
            {
                this.counter = start;
            }
    
            @Override
            public void run()
            {
                while (true)
                {
                    System.out.println(counter);
                    counter += 2;
                }
            }
    
        }
        public static void main(String[] args)
        {
            Runnable odd = new Counter(1);
            Runnable even = new Counter(2);
            Test app = new Test();
            app.submitTask(odd);
            app.submitTask(even);
        }
    }
    

    【讨论】:

    • 如果是为了练习,没有理由要求在 StackOverflow 上提供现成的解决方案。 OP 应该阅读教程,并尝试一下。
    • 添加了代码供您开始使用。请注意,当我运行它时,我得到了很多偶数,然后是很多赔率,然后是很多偶数。
    【解决方案3】:

    一些忙等待的代码,最简单的。

    package t1;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class Redx implements Runnable{
        private final static int MAX = 99;
        final AtomicInteger next;
        final int odd;
    
        public Redx(AtomicInteger next, int odd) {
            super();
            this.next = next;
            this.odd = odd;
        }
    
        public void run(){
            for(;;){
                int n = next.get();
                if (n > MAX)
                    break;
                if ((n&1)==odd)
                    continue;           
    
                System.out.print(n+", ");
                if ((n & 0x1F)==0x1F)//new line can be skipped
                    System.out.println();
                next.lazySet(n+1);
    
            }
        }
        public static void main(String[] args) {
            final AtomicInteger next = new AtomicInteger(0);
            Redx x0 = new Redx(next, 0);
            Redx x1 = new Redx(next, 1);
            new Thread(x0).start();
            new Thread(x1).start();
            for(;next.get()<=MAX;)
                    Thread.yield();
    
            System.out.println();
            System.out.println("Done!");
        }
    
    }
    

    【讨论】:

      【解决方案4】:
      public static void main(String[] args) {
          final int max = 100;
          final AtomicInteger i = new AtomicInteger(0);
          new Thread(new Runnable() {
              @Override
              public void run() {
                  while (i.get() < max) {
                      if (i.get() % 2 != 0) {
                          synchronized (i) {
                              System.out.print(" " + i.getAndAdd(1));
                          }
                      }
                  }
              }
          }).start();
          new Thread(new Runnable() {
              @Override
              public void run() {
                  while (i.get() < max) {
                      if (i.get() % 2 == 0) {
                          synchronized (i) {
                              System.out.print(" " + i.getAndAdd(1));
                          }
                      }
                  }
              }
          }).start();
          do {
              try {
                  Thread.currentThread().sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          } while (i.get() != max);
          System.out.println("\nDone");
      }
      

      【讨论】:

      • 这是我运行代码后得到的序列:0 2 1 3 5 4 6 8 7 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 36 37 38 39 40 41 49 50 51 52 53 54 50 51 52 58 59 60 61 62 63 64 65 64 62 64 69 70 72 71 73 74 74 74 74 79 79 79 79 70 82 81 83 85 84 86 88 87 89 91 90 92 93 94 95 96 98 97 99
      • 抱歉,我已经更新了代码,现在在我的机器上运行良好。
      【解决方案5】:
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.atomic.AtomicBoolean;
      import java.util.concurrent.atomic.AtomicInteger;
      import java.util.concurrent.locks.Condition;
      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
      
      public class GenerateEvenOddNumberTest {
      
          public static void main(String[] args) {
              GenerateNumber GenNum = new GenerateNumber();
              ExecutorService es =    Executors.newFixedThreadPool(2);
              es.execute(GenNum);
              es.execute(GenNum);
          }
      
      }
      
      class GenerateNumber implements Runnable{
      
          private static final AtomicInteger nextId = new AtomicInteger(0);   
      
          // Thread local variable containing each thread's ID
          private static final ThreadLocal<Integer> count =
              new ThreadLocal<Integer>() {
                  @Override protected Integer initialValue() {
                      return nextId.getAndIncrement();
              }
          };
      
      
          private static final AtomicBoolean bool = new AtomicBoolean(true);  
            // Thread local variable containing each thread's ID
          private static final ThreadLocal<Boolean> even =
              new ThreadLocal<Boolean>() {
                  @Override protected Boolean initialValue() {
                      return bool.getAndSet(false)    ;
              }
          };  
      
      
          boolean isOdd = false;  
          Lock lock = new ReentrantLock();
          Condition checkOdd = lock.newCondition();
          Condition checkEven = lock.newCondition();
      
          public void printEvenNumber(){
              lock.lock();
              try {
                  while(count.get()<500){
                      while(isOdd){
                          try {
                              checkEven.await();
                          } catch (InterruptedException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                          }
                      }
                      System.out.println("Thread Name "+Thread.currentThread().getName()+" "+count.get());
                      count.set(count.get()+2);
                      isOdd = true;
                      checkOdd.signal();
                  }
              } finally {
                  lock.unlock();
              }
          }
      
          public void printOddNumber(){
              lock.lock();
              try {       
                  while(count.get()<500){
                      while(!isOdd){
                          try {
                              checkOdd.await();
                          } catch (InterruptedException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                          }
                      }
                      System.out.println("Thread Name "+Thread.currentThread().getName()+" "+count.get());
                      count.set(count.get()+2);
                      isOdd = false;
                      checkEven.signal();
                  }
              } finally {
                  lock.unlock();
              }           
          }
      
      
          @Override
          public void run() {
              if(even.get()){
                  printEvenNumber();
              }
              else{
                  printOddNumber();
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        /* 使用 Semaphore 是打印奇偶数列的最简单方法 */

        import java.util.concurrent.ExecutorService;
        import java.util.concurrent.Executors;
        import java.util.concurrent.Semaphore;
        
        class Even implements Runnable {
        
            private Semaphore s1;
            private Semaphore s2;
            private static volatile int num = 0;
        
            Even(Semaphore s1, Semaphore s2) {
                this.s1 = s1;
                this.s2 = s2;
            }
        
            @Override
            public void run() {
                synchronized (s2) {
                    while (num < 99) {
                        try {
                            s1.acquire();
                            System.out.print(" " + num);
                            num += 2;
                            s2.release();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
        class Odd implements Runnable {
        
            private Semaphore s1;
            private Semaphore s2;
            private static volatile int num = 1;
        
            Odd(Semaphore s1, Semaphore s2) {
                this.s1 = s1;
                this.s2 = s2;
            }
        
            @Override
            public void run() {
                synchronized (s1) {
                    while (num < 100) {
                        try {
                            s2.acquire();
                            System.out.print(" " + num);
                            num += 2;
                            s1.release();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
        public class ExecOddEvenPrint {
        
            public static void main(String[] args) {
        
                ExecutorService exec = Executors.newFixedThreadPool(2);
                Semaphore s1 = new Semaphore(1);
                Semaphore s2 = new Semaphore(0);
        
                exec.execute(new Even(s1, s2));
                exec.execute(new Odd(s1, s2));
        
            }
        
        }
        

        【讨论】:

          【解决方案7】:
          This will do:
          import java.util.ArrayList;
          import java.util.List;
          import java.util.concurrent.ExecutorService;
          import java.util.concurrent.Executors;
          import java.util.concurrent.atomic.AtomicInteger;
          
          
           public class Threads implements Runnable{
          
              static AtomicInteger  x=new AtomicInteger(1);
              public  void generate()
              {
                  //System.out.println("In generate");
                synchronized(x){
                  if(x.get()%2==0)
                      System.out.println(x+" is EVEN");
                  else
                      System.out.println(x+" is ODD");
                  x.incrementAndGet();
                  }
          
              }
              @Override
              public synchronized void run() {        
                  //System.out.println("In run");
                  generate();
              }
          
              public static void main(String[] args) {
                  //System.out.println("In generateThreads");
                      ExecutorService pool=Executors.newFixedThreadPool(10);
                      for(int i=0;i<2;i++) // two threads
                      pool.submit(new Threads());
                      pool.shutdown();
                      while (!pool.isTerminated()) {
          
                      }
                   //   System.out.println("DONEs");
          
              }
          
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-05-17
            • 1970-01-01
            • 1970-01-01
            • 2011-08-26
            • 2019-03-17
            • 2021-10-15
            • 1970-01-01
            相关资源
            最近更新 更多