java - 快餐程序、多线程和信号量Java

标签 java multithreading

因此,我在编程之旅中短暂地偶然发现了信号量,最近我自己设计了一个复制快餐链式店的程序。

我会尽力解释,如果需要更彻底,请在评论部分告诉我

计划:

有一个生产者和一个消费者(收银员和 worker ),因此收银员接受订单(放置它们在缓冲区中,因此是一个循环数组..)并且工作人员处理该订单(从循环数组中获取订单)

我正在尝试实现信号量,以便在发出订单后,在工作人员处理订单之前无法使用特定的收银台。并且还使用信号量,以便军官一次只能发出一个命令

主要方法如下:

public class FastFood {

    /**
     * @param args the command line arguments
     */
    static Buffer buff = new Buffer(2);
    static Semaphore semWorker = new Semaphore(1);
    static Semaphore semTills = new Semaphore(1);
    static int totalOrders = 10;
    static int startOrders = 0;
    static int processedOrders = 0;

    public static void main(String[] args) {
        // TODO code application logic here

        int numberOfWorkers = 2;
        int numberOfTills = 3;
        int numberOfFoodChoices = 4;
        Random rand = new Random();

        Tills[] tills = new Tills[numberOfTills];
        Worker[] workers = new Worker[numberOfWorkers];

        //int tillId, int foodId, Buffer buff
        for (int i = 0; i < tills.length; i++) {
            int foodId = rand.nextInt(numberOfFoodChoices) + 1;
            tills[i] = new Tills(i, foodId, buff);
            tills[i].start();
        }

        //int workerId, Buffer buff
        for (int i = 0; i < workers.length; i++) {
            workers[i] = new Worker(i, buff);
            workers[i].start();
        }

        for (Tills till : tills) {
            try {
                till.join();
            }catch (InterruptedException ex) {
                System.out.println(ex);
            }
        }

        for (Worker worker : workers) {
            try {
                worker.join();
            }catch (InterruptedException ex) {
                System.out.println(ex);
            }
        }

正如您通过 main 方法所看到的,我正在循环并运行工作线程和收银台的线程数组。

这是收银台类。这样就创建了订单。您将能够看到我正在使用 FastFood.semTills.down() 和 FastFood.semTills.up() 这是使用信号量。所以向下是获取信号量,向上是释放信号量。 但是问题是我对这些信号量升降的定位逻辑。

public class Tills extends Thread {
    private final Buffer buff;
    private final int foodId;
    private final int tillId;

    public Tills(int tillId, int foodId, Buffer buff) {
        this.tillId = tillId;
        this.foodId = foodId;
        this.buff = buff;
    }

    @Override
    public void run(){
        FastFood.semTills.down();
        while(FastFood.startOrders < FastFood.totalOrders){
            FastFood.semTills.up();
            buff.acquire(); 
            while(buff.isFull()){
                try {
                    buff.release();
                    sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Tills.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            FastFood.startOrders++;
            Order v = new Order(foodId, tillId);
            System.out.println(v.toString());            
            try {
                Random n = new Random();
                int time = n.nextInt(100) + 1;
                buff.release();
                sleep(time);
                buff.insert(v);
            } catch (InterruptedException ex) {
                System.out.println(ex);
            }

        }
    }

worker类有点相同,但我想确保一次只有一个worker可以处理一个特定的订单(启用多个worker来处理多个订单也可以)

public class Worker extends Thread{
    private final int workerId;
    private final Buffer buff;


    public Worker(int workerId, Buffer buff) {
        this.workerId = workerId;
        this.buff = buff;
    }

    public void run(){
        FastFood.semWorker.down();
        while(FastFood.totalOrders>FastFood.processedOrders){
            buff.acquire();
            while(buff.isEmpty()){
                FastFood.semWorker.up();
                try {
                    buff.release();
                    sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            FastFood.processedOrders++;
            System.out.print("Worker: " + workerId);
            buff.remove();
            buff.release();
            try {
                Random n = new Random();
                int time = n.nextInt(100) + 1;
                sleep(time);
            } catch (InterruptedException ex) {
                System.out.println(ex);
            }

        }
        FastFood.semWorker.up();
    }

这是我得到的输出,你可以看到它没有等待订单被处理,因此我的信号量的定位一定是错误的,我已经尝试了各种可能性:

run:
FoodId: 3 TillId : 1 Order Count : 0
FoodId: 3 TillId : 0 Order Count : 1
FoodId: 4 TillId : 2 Order Count : 2
FoodId: 4 TillId : 2 Order Count : 3
FoodId: 4 TillId : 2 Order Count : 4
FoodId: 3 TillId : 0 Order Count : 5
FoodId: 3 TillId : 0 Order Count : 6
Worker: 1 Food: 3 TillId: 0
Worker: 0 Food: 3 TillId: 0
FoodId: 3 TillId : 0 Order Count : 7
FoodId: 3 TillId : 0 Order Count : 8
Worker: 1 Food: 3 TillId: 0
FoodId: 3 TillId : 0 Order Count : 9
FoodId: 3 TillId : 1 Order Count : 10
Worker: 0 Food: 3 TillId: 0
Worker: 1 Food: 3 TillId: 1
Worker: 0 Food: 3 TillId: 0
Worker: 1 Food: 4 TillId: 2
Worker: 0 Food: 3 TillId: 0
Worker: 1 Food: 4 TillId: 2
Worker: 0 Food: 3 TillId: 0
10

快速类(class)简介:

FastFood:Main,创建线程 Buffer:用于循环数组 订单:存储从什么时间到什么时间的食物 Tills:创建订单 Worker:处理订单

信号量:

package fastfood;

public class Semaphore {

    private int count;

    public Semaphore(int n) {
        count = n;
    }

    public synchronized void down() {

        while (count == 0) {

            try {
                wait(); // Blocking call.
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }
        count--;
    }

    public synchronized void up() {
        count++;
        notify();
    }
}

缓冲区:

public class Buffer {
    private int size;
    private int inPtr = 0;
    private int outPtr = 0;
    private int counter = 0;
    private Order[] data; 
    private Semaphore sem = new Semaphore(1);

    public Buffer(int size) {
        this.size = size;
        this.data = new Order[size];
    }

    public Order remove(){
        // removes the revote for the officer 
        Order out;
        out = data[outPtr];
        System.out.println(" Food: " + out.getFoodId() + " TillId: " + 
            out.getTillId());
        outPtr = (outPtr+1)%size;
        counter--;
        return out;
    }
    public void insert(Order i){
        // inserts a new vote 
        data[inPtr] = i;
        inPtr = (inPtr+1)%size;
        counter++;
    }
    public boolean isEmpty(){
        // returns true if empty
        return counter==0;
    }
    public boolean isFull(){
        // returns true if full
        return counter==size;
    }
    public void acquire(){
        sem.down();
    }
    public void release(){
        sem.up();
    }

}

变化:

更改2:

worker 类(Class):

public void run() {
       while(FastFood.processedOrders < FastFood.totalOrders){
           try{
                buff.acquire();
                FastFood.semWorker.down();
                while(buff.isEmpty()){
                    try {
                        sleep(100);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                try{
                Order o = buff.remove();
                System.out.println(o.toString() + " FoodId: " + o.getFoodId() 
                        + " TillId: " + o.getTillId());
                FastFood.processedOrders++;
                }catch(Exception e){
                    System.out.println(e);
                }
           }finally{
               buff.release();
               FastFood.semTills.up();
           }

       }

Tills 类:

while (FastFood.startOrders < FastFood.totalOrders) {
            try {
                buff.acquire();
                FastFood.semTills.down();
                while (buff.isFull()) {
                    try {
                        sleep(100);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Tills.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                try {
                    Order o = new Order(foodId, tillId);
                    System.out.println(o.toString());
                    buff.insert(o);
                    FastFood.startOrders++;
                } catch (Exception e) {
                    System.out.println(e);
                }
            } finally {
                buff.release();
                FastFood.semWorker.up(); 
            }

订单:

public class Order {
    private final int foodId;
    private final int tillId;
    static int count = 0;
    private int orderCount=0;

    public Order(int foodId, int tillId){
        this.foodId = foodId;
        this.tillId = tillId;
        this.orderCount = count++;
    }

    public int getFoodId() {
        return foodId;
    }

    public int getTillId() {
        return tillId;
    }

    public static int getCount() {
        return count;
    }

    public int getOrderCount() {
        return orderCount;
    }


    @Override
    public String toString() {
        return "FoodId: " +foodId+" TillId : "+tillId+" Order Count : "+ orderCount; 
    }

最佳答案

在 while 循环之后立即释放锁有什么原因吗?在您 checkin while 循环后,您的钱柜就会立即释放它们。这看起来很令人困惑。您希望收银机线程在订单完成后 hibernate ,并仅在订单完成后才唤醒吗?您希望您的 worker 只专门执行某个订单吗?难道只要有订单在缓冲区等待,工作人员就不能处理任何订单吗?抱歉,我无法发表评论,因为我没有 50 名代表。

快餐

import java.util.*;

public class FastFood {

/**
 * @param args the command line arguments
 */
static Buffer buff = new Buffer(2);
static Semaphore semWorker = new Semaphore(2);
static Semaphore semTills = new Semaphore(2);
static int totalOrders = 10;
static int startOrders = 0;
static int processedOrders = 0;

public static void main(String[] args) {
    // TODO code application logic here

    int numberOfWorkers = 2;
    int numberOfTills = 3;
    int numberOfFoodChoices =4;
    Random rand = new Random();

    Tills[] tills = new Tills[numberOfTills];
    Worker[] workers = new Worker[numberOfWorkers];

    //int tillId, int foodId, Buffer buff
    for (int i = 0; i < tills.length; i++) {
        int foodId = rand.nextInt(numberOfFoodChoices) + 1;
        tills[i] = new Tills(i, foodId, buff);
        tills[i].start();
    }

    //int workerId, Buffer buff
    for (int i = 0; i < workers.length; i++) {
        workers[i] = new Worker(i, buff);
        workers[i].start();
    }

    for (Tills till : tills) {
        try {
            till.join();
        }catch (InterruptedException ex) {
            System.out.println(ex);
        }
    }

    for (Worker worker : workers) {
        try {
            worker.join();
        }catch (InterruptedException ex) {
            System.out.println(ex);
        }
    }
}
}

缓冲区

public class Buffer {
private int size;
private int inPtr = 0;
private int outPtr = 0;
private int counter = 0;
private Order[] data; 


public Buffer(int size) {
    this.size = size;
    this.data = new Order[size];
}

public synchronized String remove(){
    // removes the revote for the officer 
    Order out;
    out = data[outPtr];
    outPtr = (outPtr+1)%size;
    counter--;
    return " Food: " + out.getFoodId() + " ordered by TillId: " + out.getTillId();
}
public synchronized void insert(Order i){
    // inserts a new vote 
    data[inPtr] = i;
    inPtr = (inPtr+1)%size;
    counter++;
}
public synchronized boolean isEmpty(){
    // returns true if empty
    return counter==0;
}
public synchronized boolean isFull(){
    // returns true if full
    return counter==size;
}


}

直到

public class Tills extends Thread {
private final Buffer buff;
private final int foodId;
private final int tillId;

public Tills(int tillId, int foodId, Buffer buff) {
    this.tillId = tillId;
    this.foodId = foodId;
    this.buff = buff;
}

public void run(){
    while(FastFood.startOrders < FastFood.totalOrders){
        FastFood.semTills.down();

        while(buff.isFull()){
            try {
                sleep(100);
            } catch (InterruptedException ex) {
                //Logger.getLogger(Tills.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        FastFood.startOrders++;
        Order v = new Order(foodId, tillId);
        buff.insert(v);
        System.out.println("Till number " + tillId + " created a new order " + foodId + " to be processed");
        FastFood.semWorker.up();

    }
}
}

worker

public class Worker extends Thread{
private final int workerId;
private final Buffer buff;


public Worker(int workerId, Buffer buff) {
    this.workerId = workerId;
    this.buff = buff;
}

 public void run() {
    while (FastFood.totalOrders > FastFood.processedOrders) {
        FastFood.semWorker.down();
        while (buff.isEmpty()) {
            try {
                sleep(100);
            } catch (InterruptedException ex) {
                //Logger.getLogger(Worker.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        //FastFood.processedOrders++;
        System.out.println("Worker: " + workerId + " completed order number " + buff.remove() + " total orders processed so far: " + FastFood.processedOrders++);

        FastFood.semTills.up();
        try {
            Random n = new Random();
            int time = n.nextInt(100) + 1;
            sleep(time);
        } catch (InterruptedException ex) {
            System.out.println(ex);
        }
    }
 }
}

不确定这是否像您的订单类别

public class Order{
private int tillID;
private int foodID;
public Order(int food, int till){
    tillID = till;
    foodID = food;
}

int getFoodId(){
    return foodID;
}

int getTillId(){
    return  tillID;
}

}

在尝试之前请注意,它并非 100% 正确。我删除了缓冲区中的信号量,只是使方法同步。如果您将快餐中的信号量值更改为 1,它将无法完全运行,因为并非所有线程都能够唤醒并在最后加入以退出程序。

此外,使用totalOrders和processsOrders的静态变量作为控制线程何时停止运行的方式似乎令人担忧,因为我认为每个线程都有自己的副本,因此它也可能导致竞争条件。但我可能是错的。我不确定你还没看过什么,但我想this has some good information that might help

关于java - 快餐程序、多线程和信号量Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34324794/

相关文章:

c# - 当我断开一个客户端套接字时 Windows 服务关闭

ios - 我如何在另一个线程的运行循环中安排时间?

multithreading - 如何将对堆栈变量的引用传递给线程?

java - 如何从 JSON 响应中提取 boolean 值?

java - 将类传递给另一个方法

java - 如何解决 Android Java 中的并发问题?

c# - 如何在多线程应用程序中执行文件日志记录

java - POI 堆空间异常或 Excel 2007 的任何替代 java api?

java - MongoDB 检查插入

c++ - 多线程文件流