Java:如何使用 Executor 框架从 2 个单独的线程中打印奇数和偶数

Posted

技术标签:

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

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

【问题讨论】:

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

【讨论】:

如果是为了练习,没有理由要求在 *** 上提供现成的解决方案。 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");

    


【讨论】:

以上是关于Java:如何使用 Executor 框架从 2 个单独的线程中打印奇数和偶数的主要内容,如果未能解决你的问题,请参考以下文章

2,Executor线程池

Java并发Executor框架

Java线程池Executor框架详解

Executor框架

Executor框架

Executor框架