因此,我在编程之旅中短暂地偶然发现了信号量,最近我自己设计了一个复制快餐链式店的程序。
我会尽力解释,如果需要更彻底,请在评论部分告诉我
计划:
有一个生产者和一个消费者(收银员和 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/