【问题标题】:Can FairSync guarantee the order of execution?FairSync 能保证执行顺序吗?
【发布时间】:2019-09-10 03:24:04
【问题描述】:

我的第一个问题,感谢您的帮助! 我正在尝试使用两个线程交替打印奇数和偶数 1~100。 预期结果:

    pool-1-thread-1=> 1
    pool-1-thread-2=> 2
    pool-1-thread-1=> 3
    pool-1-thread-2=> 4
    ......
    pool-1-thread-1=> 99
    pool-1-thread-2=> 100

我想我可以使用 FairSync,但它只能保证大部分打印是正确的。像这样:

pool-1-thread-1=> 55
pool-1-thread-2=> 56
pool-1-thread-1=> 57
pool-1-thread-2=> 58   
pool-1-thread-2=> 59  //※error print※
pool-1-thread-1=> 60
pool-1-thread-2=> 61
pool-1-thread-1=> 62

不知道为什么在极少数情况下会丢失订单? 你可以批评我的代码和我的英语。 这是我的代码:

private static final int COUNT = 100;

private static final int THREAD_COUNT = 2;

private static int curr = 1;

static ReentrantLock lock = new ReentrantLock(true);

static ExecutorService executorService = Executors.newCachedThreadPool();

public static void main(String[] args) {
    Runnable task = () -> {
        for (; ; ) {
            try {
                lock.lock();
                if (curr <= COUNT) {
                    System.out.println(Thread.currentThread().getName() + "=> " + curr++);
                } else {
                    System.exit(0);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    };
    for (int i = 0; i < THREAD_COUNT; i++) {
        executorService.execute(task);
    }
}

【问题讨论】:

标签: java multithreading reentrantlock


【解决方案1】:

不,亲爱的,您的实现不正确。哪个线程有机会运行由操作系统决定。不能保证线程 1 & 2 会一个接一个地执行。

您可以通过检查变量 curr 的先前值来修复您的代码,如果该值不是该线程期望的值,则不要递增和打印。

例如:

if(curr.threadName.equals("Thread 2") && (curr%2 !=0))
{
// Print
// Increment
}

【讨论】:

    【解决方案2】:

    您不能使用单锁来实现这一点。即使ReentrantLock 提供了公平性,但它无法控制线程调度。

    我们可以像Semaphore一样实现throw线程间通信。信号量控制线程执行。

    我们创建了两个线程,一个奇数线程和一个偶数线程。奇数线程打印从 1 开始的奇数,偶数线程打印从 2 开始的偶数。

    创建两个信号量,semOdd 和 semEven,它们将有 1 和 0 的许可开始。这将确保先打印奇数。

    class SharedPrinter {
    
        private Semaphore semEven = new Semaphore(0);
        private Semaphore semOdd = new Semaphore(1);
    
        void printEvenNum(int num) {
            try {
                semEven.acquire();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println(Thread.currentThread().getName() + num);
            semOdd.release();
        }
    
        void printOddNum(int num) {
            try {
                semOdd.acquire();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println(Thread.currentThread().getName() + num);
            semEven.release();
    
        }
    }
    
    class Even implements Runnable {
        private SharedPrinter sp;
        private int max;
    
        // standard constructor
    
        @Override
        public void run() {
            for (int i = 2; i <= max; i = i + 2) {
                sp.printEvenNum(i);
            }
        }
    }
    
    class Odd implements Runnable {
        private SharedPrinter sp;
        private int max;
    
        // standard constructors 
        @Override
        public void run() {
            for (int i = 1; i <= max; i = i + 2) {
                sp.printOddNum(i);
            }
        }
    }
    
    public static void main(String[] args) {
        SharedPrinter sp = new SharedPrinter();
        Thread odd = new Thread(new Odd(sp, 10),"Odd");
        Thread even = new Thread(new Even(sp, 10),"Even");
        odd.start();
        even.start();
    }
    

    参考:here

    【讨论】:

    • 您可以为此使用一个 Lock 并使用两个 Condition 对象。也可以提出一个单一的Condition 实现。
    猜你喜欢
    • 2018-01-07
    • 2016-04-29
    • 1970-01-01
    • 2014-09-09
    • 2021-03-07
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2016-05-02
    相关资源
    最近更新 更多