【问题标题】:Circular Threads in Java using SemaphoresJava中使用信号量的循环线程
【发布时间】:2019-07-08 17:38:09
【问题描述】:

我想使用 4 个线程和信号量来实现 FizzBizz 游戏。
我设法使线程以所需的顺序工作:fizz() -> buzz() -> fizzBuzz() -> printNumber().
但是,我无法使整个过程循环。
每个方法都有自己的信号量,尽管在释放下一个方法信号量之前锁定了自己的信号量,但这些方法不会挂在第二个获取上(实际上这是方法中的第一个)。

期望的行为:
1. 锁定所有信号量。
2. 启动所有 4 种方法。
3.释放fizz()信号量,让它先行。
4. fizz() 完成,释放buzz() 锁并挂起,直到printNumber() 释放它。
5.等

import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;

class FizzBuzz {
    protected AtomicLong num = new AtomicLong(1);
    protected AtomicLong n = new AtomicLong(100);
    protected Semaphore sem1 = new Semaphore(1);
    protected Semaphore sem2 = new Semaphore(1);
    protected Semaphore sem3 = new Semaphore(1);
    protected Semaphore sem4 = new Semaphore(1);

    public void start() {
        System.out.println("Started");
        try {
            sem1.acquire();
            sem2.acquire();
            sem3.acquire();
            sem4.acquire();
            this.fizz();
            this.buzz();
            this.fizzBuzz();
            this.printNumber();
            sem1.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void fizz() {
        new Thread() {
            @Override
            public void run() {
                while (num.get() <= n.get()) {
                    try {
                        // System.out.println("Fizz waiting...");
                        sem1.acquire();
                        sem1.release();
                        if (num.get() > n.get()) {
                            break;
                        }
                        if (num.get() % 3 == 0 && num.get() % 5 != 0) {
                            num.getAndIncrement();
                            System.out.println("Fizz");
                        }
                        sem1.acquire();
                        sem2.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    public void buzz() {
        new Thread() {
            @Override
            public void run() {
                while (num.get() <= n.get()) {
                    try {
                        // System.out.println("Buzz waiting...");
                        sem2.acquire();
                        sem2.release();
                        if (num.get() > n.get()) {
                            break;
                        }
                        if (num.get() % 5 == 0 && num.get() % 3 != 0) {
                            num.getAndIncrement();
                            System.out.println("Buzz");
                        }
                        sem2.acquire();
                        sem3.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    public void fizzBuzz() {
        new Thread() {
            @Override
            public void run() {
                while (num.get() <= n.get()) {
                    try {
                        // System.out.println("FizzBuzz waiting...");
                        sem3.acquire();
                        sem3.release();
                        if (num.get() > n.get()) {
                            break;
                        }
                        if (num.get() % 3 == 0 && num.get() % 5 == 0) {
                            num.getAndIncrement();
                            System.out.println("FizzBuzz");
                        }
                        sem3.acquire();
                        sem4.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    public void printNumber() {
        new Thread() {
            @Override
            public void run() {
                while (num.get() <= n.get()) {
                    try {
                        // System.out.println("Print Number waiting...");
                        sem4.acquire();
                        sem4.release();
                        if (num.get() > n.get()) {
                            break;
                        }
                        if (num.get() % 3 == 1 && num.get() % 5 == 1) {
                            num.getAndIncrement();
                            System.out.println(num);
                        }
                        sem4.acquire();
                        sem1.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

【问题讨论】:

    标签: java concurrency semaphore


    【解决方案1】:

    如果你坚持这种方式,我只是编写使用五个信号量的代码,因为四个信号量不能形成一个稳定的循环。

    package exercise.concurrency;
    import java.util.concurrent.Semaphore;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicLong;
    
    public class SemaphoreTest {
        public static void main(String[] args) {
            new FizzBuzz().start();
        }
    
    }
    
    
    
    
    class FizzBuzz {
        protected AtomicLong num = new AtomicLong(1);
        protected AtomicLong n = new AtomicLong(100);
        protected Semaphore sem1 = new Semaphore(1);
        protected Semaphore sem2 = new Semaphore(1);
        protected Semaphore sem3 = new Semaphore(1);
        protected Semaphore sem4 = new Semaphore(1);
        protected Semaphore sem5 = new Semaphore(1);
    
        public void start() {
            System.out.println("Started");
            try {
                sem1.acquire();
                sem2.acquire();
                sem3.acquire();
                sem4.acquire();
                sem5.acquire();
                this.fizz();
                this.buzz();
                this.fizzBuzz();
                this.printNumber();
    
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void fizz() {
            new Thread() {
                @Override
                public void run() {
                     sem1.release();
                     sem5.release();
                    while (num.get() <= n.get()) {
                        try {
                            sem1.acquire();
                            sem5.acquire();
                            if (num.get() > n.get()) {
                                break;
                            }
                            if (num.get() % 3 == 0 && num.get() % 5 != 0) {
                                num.getAndIncrement();
                                System.out.println("Fizz");
                            }
                            System.out.println("1.fizz one loop");
                            TimeUnit.MILLISECONDS.sleep(500);
                            sem2.release();
                            sem5.release();
                            Thread.yield();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("fizz has finshed");
                }
            }.start();
        }
    
        public void buzz() {
            new Thread() {
                @Override
                public void run() {
                    while (num.get() <= n.get()) {
                        try {
                            sem2.acquire();
                            sem5.acquire();
                            if (num.get() > n.get()) {
                                break;
                            }
                            if (num.get() % 5 == 0 && num.get() % 3 != 0) {
                                num.getAndIncrement();
                                System.out.println("Buzz");
                            }
                           System.out.println("2.buzz one loop");
                           TimeUnit.MILLISECONDS.sleep(500);
                           sem3.release();
                           sem5.release();
                           Thread.yield();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    
        public void fizzBuzz() {
            new Thread() {
                @Override
                public void run() {
                    while (num.get() <= n.get()) {
                        try {
                            sem3.acquire();
                            sem5.acquire();
                            if (num.get() > n.get()) {
                                break;
                            }
                            if (num.get() % 3 == 0 && num.get() % 5 == 0) {
                                num.getAndIncrement();
                                System.out.println("FizzBuzz");
                            }
                            System.out.println("3.fizzBuzz one loop");
                            TimeUnit.MILLISECONDS.sleep(500);
                            sem4.release();
                            sem5.release();
                            Thread.yield();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    
        public void printNumber() {
            new Thread() {
                @Override
                public void run() {
                    while (num.get() <= n.get()) {
                        try {
                            sem4.acquire();
                            sem5.acquire();
                            if (num.get() > n.get()) {
                                break;
                            }
                            if (num.get() % 3 == 1 && num.get() % 5 == 1) {
                                num.getAndIncrement();
                                System.out.println(num);
                            }
                            System.out.println("4.printNumber one loop\n");
                            TimeUnit.MILLISECONDS.sleep(500);
                            sem1.release();
                            sem5.release();
                            Thread.yield();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    }
    

    它使用Thread.yield() 为线程引擎提供建议,当一个线程执行一次,另一个线程有机会执行他的工作。TimeUnit.Millseconds.sleep() 使结果看起来更清晰。

    结果如下:

    Started
    1.fizz one loop
    2.buzz one loop
    3.fizzBuzz one loop
    2
    4.printNumber one loop
    
    1.fizz one loop
    2.buzz one loop
    3.fizzBuzz one loop
    4.printNumber one loop
    
    1.fizz one loop
    2.buzz one loop
    3.fizzBuzz one loop
    4.printNumber one loop
    
    1.fizz one loop
    2.buzz one loop
    3.fizzBuzz one loop
    4.printNumber one loop
    
    1.fizz one loop
    2.buzz one loop
    3.fizzBuzz one loop
    4.printNumber one loop
    
    1.fizz one loop
    ...
    

    【讨论】:

      猜你喜欢
      • 2013-03-21
      • 2012-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-30
      相关资源
      最近更新 更多