我有一个线程子类,它代表到达公职的人,还有一个线程子类,代表个案工作者。
每次到达一个人时,都会输入该人的名字。办公室有2个入口,入境者可在其中输入姓名。等候室最多只能容纳10人。如果还有更多,他们必须等到有空位为止。
个案工作者呼叫输入的姓名。有2个个案工作者。当然,只有输入名称并按输入顺序(如队列)调用它们,才能调用名称。当所有的名字都调出来后,案例工作者必须等到更多的人到来。
到达者和案例工作者的线程每次都在随机数秒(从1到10秒)内进入睡眠状态。
我还有一个公共类,该类包含一个带有名称列表的arraylist作为方法,以及一些用于调用名称和输入名称的方法。它还包含用于解决此问题的append和take方法(java的监视器)。
到目前为止,这是我的代码:
import java.util.Random;
public class ThreadClass_Arrivals extends Thread {
private CommonClass commonClass;
public int threadID;
public ThreadClass_Arrivals(CommonClass commonClass, int threadID) {
this.commonClass = commonClass;
this.threadID = threadID;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
// time interval before a name is entered - the thread sleep between 1-10 seconds every time
Random random = new Random();
int randomNumber = random.nextInt(10) + 1;
int numberInThousand = randomNumber * 1000;
try {
Thread.sleep(numberInThousand);
} catch (InterruptedException e) {
e.printStackTrace();
}
commonClass.enterName(commonClass.namesList().get(commonClass.nameEnteredIndex), this.threadID);
// java monitor
commonClass.append((char) commonClass.nameEnteredIndex);
}
}
}
import java.util.Random;
public class ThreadClass_Caseworkers extends Thread {
private CommonClass commonClass;
public int threadID;
public ThreadClass_Caseworkers(CommonClass commonClass, int threadID) {
this.commonClass = commonClass;
this.threadID = threadID;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
// Time interval before a name is called - The thread sleep between 1-10 seconds every time
Random random = new Random();
int randomNumber = random.nextInt(10) + 1;
int numberInThousand = randomNumber * 1000;
try {
Thread.sleep(numberInThousand);
} catch (InterruptedException e) {
e.printStackTrace();
}
// java monitor
commonClass.take((char) commonClass.nameEnteredIndex);
commonClass.callAName(this.threadID, commonClass.nameCalledIndex);
}
}
}
import java.util.ArrayList;
public class CommonClass {
// java monitor
int N = 10;
char[] buffer = new char[N];
int nextin, nextout, count;
public int nameEnteredIndex;
public int nameCalledIndex;
// names list with 20 names
public ArrayList<String> namesList() {
ArrayList<String> names = new ArrayList<>();
names.add("Hans");
names.add("Jens");
names.add("Rasmus");
names.add("Kasper");
names.add("Niels");
names.add("Torben");
names.add("Peter");
names.add("Michael");
names.add("Lars");
names.add("Anders");
names.add("Bo");
names.add("Klaus");
names.add("Ib");
names.add("Kevin");
names.add("Oscar");
names.add("Nicolaj");
names.add("Alexander");
names.add("Morten");
names.add("Carsten");
names.add("Jakob");
return names;
}
public synchronized void enterName(String name, int threadID) {
if (threadID == 0) {
System.out.println("Name-entered (entrance1): " + name);
} else if (threadID == 1) {
System.out.println("Name-entered (entrance2): " + name);
}
nameEnteredIndex++;
}
public synchronized void callAName(int threadID, int index) {
if (threadID == 0) {
System.out.println("Name called (caseworker1): " + namesList().get(index));
} else if (threadID == 1) {
System.out.println("Name called (caseworker2): " + namesList().get(index));
}
nameCalledIndex++;
}
// java monitor
public synchronized void append(char x) {
if (count == N) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer[nextin] = x;
nextin = (nextin + 1) % N;
count++;
notifyAll();
}
// java monitor
public synchronized void take(char x) {
if (count == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
x = buffer[nextout];
nextout = (nextout + 1) % N;
count--;
notifyAll();
}
}
public class MainApp {
public static void main(String[] args) {
// commonclass
CommonClass commonClass = new CommonClass();
// Thread - arrivals
ThreadClass_Arrivals threadClass_arrival1 = new ThreadClass_Arrivals(commonClass, 0);
ThreadClass_Arrivals threadClass_arrival2 = new ThreadClass_Arrivals(commonClass, 1);
threadClass_arrival1.start();
threadClass_arrival2.start();
// Thread - caseworkers
ThreadClass_Caseworkers threadClass_caseworker1 = new ThreadClass_Caseworkers(commonClass, 0);
ThreadClass_Caseworkers threadClass_caseworker2 = new ThreadClass_Caseworkers(commonClass, 1);
threadClass_caseworker1.start();
threadClass_caseworker2.start();
}
}
问题在于,即使在列表中有20个名称,也要在输入某些名称之前调用一些名称,而且还会得到ArrayOutOfBounceException,并且有一个循环从2个线程子类中的列表中检索20个名称。
任何帮助将不胜感激!
答案 0 :(得分:1)
您提出的问题的细节很复杂,但是我可以帮助您了解生产者/消费者问题中如何使用java的监视器(wait,notify,notifyAll)。
这是需要完成的工作队列的中心。此队列(或其他有序数据结构)需要具有两个同步的方法:弹出作业,然后推送作业
synchronized void push(T) {
myInternalQueue.push(T);
notify();
}
synchronized T pop {
if (myInternalQueue.length() == 0) { // you can also use while here, if a thread could wake up and the queue might still be empty
wait();
}
return myInternalQueue.pop();
}
Consumer
线程调用pop以获取下一个作业。如果没有下一个作业,则Producer
线程将另一个作业推入队列并调用notify时,线程等待被唤醒。请注意,在我给出的示例中,由于两种方法已经同步,因此在pop和push中不需要内部同步块
答案 1 :(得分:0)
这是使用Ada编程的非常相似的问题的解决方案。 在此解决方案中,生产者和消费者一直运行,直到主要任务发出停止信号。以这种方式,客户数量是由时间而不是简单的循环计数来控制的。 每个生产者都通过他们进入的门为客户命名,以便我们可以看到两个生产者都在工作。在处理客户时,每个业务员都将标识每个客户。 “等候室”实现为包含10个元素的同步队列。同步队列处理所有数据同步问题,包括队列满时挂起生产者和队列空时挂起文员(消费者)。
Ada在程序包中定义程序模块。每个软件包必须具有一个规范,该规范定义了模块的公共接口和私有接口。软件包通常还具有定义模块行为的主体。主过程创建生产者任务类型和消费者任务类型的实例,这些实例立即开始运行。然后主机延迟(睡眠)80秒,并为每个任务调用“停止”条目。
-----------------------------------------------------------------------
-- Services package
--
-- This package defines a synchronized bounded queue holding the
-- names of customers in a service industry.
--
-- It also defines a producer task type which simulates customers
-- entering a waiting room (the synchronized queue) and a consumer
-- task type simulating a person serving people in the waiting
-- room.
-----------------------------------------------------------------------
package Simulation is
type Door_Type is (Front, Back);
type Clerk_Type is(Herman, Jill);
task type Producer(Door : Door_Type) is
Entry Stop;
end Producer;
task type Consumer(Clerk : Clerk_Type) is
Entry Stop;
end Consumer;
end Simulation;
包装体为:
with Ada.Containers.Synchronized_Queue_Interfaces;
with Ada.Containers.Bounded_Synchronized_Queues;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers; use Ada.Containers;
package body Simulation is
package Queue_Interface is new Ada.Containers.Synchronized_Queue_Interfaces
(Unbounded_String);
use Queue_Interface;
package Bounded_Queue is new Ada.Containers.Bounded_Synchronized_Queues
(Queue_Interface, 10);
use Bounded_Queue;
Seed : Generator;
Waiting_Room : Bounded_Queue.Queue;
--------------
-- Producer --
--------------
task body Producer is
Name : Unbounded_String;
Count : Positive := 1;
Sleep : Float;
begin
loop
select
accept Stop;
exit;
else
Name := To_Unbounded_String(Door'Image & " " & Count'Image);
Count := Count + 1;
Waiting_Room.Enqueue(Name);
Put_Line(" " & To_String(Name) & " entered waiting room.");
Sleep := (Random(Seed) * 9.0) + 1.0;
delay Duration(Sleep);
end select;
end loop;
Put_Line(" Producer " & Door'Image & " is finished.");
end Producer;
--------------
-- Consumer --
--------------
task body Consumer is
Name : Unbounded_String;
Sleep : Float;
begin
Loop
select
accept Stop;
exit;
else
select
Waiting_Room.Dequeue(Name);
Put_Line(Clerk'Image & " is now serving " & To_String(Name));
Sleep := (Random(Seed) * 9.0) + 1.0;
delay duration(sleep);
or
delay 0.001;
end select;
end select;
end loop;
while Waiting_Room.Current_Use > 0 loop
select
Waiting_Room.Dequeue(Name);
Put_Line(Clerk'Image & " is now serving " & To_String(Name));
Sleep := (Random(Seed) * 9.0) + 1.0;
delay duration(sleep);
else
exit;
end select;
end loop;
Put_Line(" Clerk " & Clerk'Image & " is finished.");
end Consumer;
begin
Reset(Seed);
end Simulation;
该程序的主要过程是:
with Simulation; use Simulation;
procedure Main is
P1 : Producer(Front);
P2 : Producer(Back);
C1 : Consumer(Herman);
C2 : Consumer(Jill);
begin
delay 80.0;
P1.Stop;
P2.Stop;
C1.Stop;
C2.Stop;
end Main;
最后,执行此程序的输出为:
FRONT 1 entered waiting room.
BACK 1 entered waiting room.
HERMAN is now serving FRONT 1
JILL is now serving BACK 1
FRONT 2 entered waiting room.
HERMAN is now serving FRONT 2
FRONT 3 entered waiting room.
JILL is now serving FRONT 3
BACK 2 entered waiting room.
HERMAN is now serving BACK 2
FRONT 4 entered waiting room.
HERMAN is now serving FRONT 4
BACK 3 entered waiting room.
JILL is now serving BACK 3
BACK 4 entered waiting room.
JILL is now serving BACK 4
FRONT 5 entered waiting room.
HERMAN is now serving FRONT 5
FRONT 6 entered waiting room.
FRONT 7 entered waiting room.
JILL is now serving FRONT 6
BACK 5 entered waiting room.
HERMAN is now serving FRONT 7
FRONT 8 entered waiting room.
FRONT 9 entered waiting room.
JILL is now serving BACK 5
HERMAN is now serving FRONT 8
BACK 6 entered waiting room.
FRONT 10 entered waiting room.
HERMAN is now serving FRONT 9
JILL is now serving BACK 6
BACK 7 entered waiting room.
HERMAN is now serving FRONT 10
FRONT 11 entered waiting room.
HERMAN is now serving BACK 7
BACK 8 entered waiting room.
JILL is now serving FRONT 11
HERMAN is now serving BACK 8
FRONT 12 entered waiting room.
HERMAN is now serving FRONT 12
BACK 9 entered waiting room.
JILL is now serving BACK 9
FRONT 13 entered waiting room.
JILL is now serving FRONT 13
HERMAN is now serving BACK 10
BACK 10 entered waiting room.
BACK 11 entered waiting room.
FRONT 14 entered waiting room.
HERMAN is now serving BACK 11
BACK 12 entered waiting room.
HERMAN is now serving FRONT 14
JILL is now serving BACK 12
BACK 13 entered waiting room.
FRONT 15 entered waiting room.
HERMAN is now serving BACK 13
JILL is now serving FRONT 15
BACK 14 entered waiting room.
JILL is now serving BACK 14
FRONT 16 entered waiting room.
JILL is now serving FRONT 16
BACK 15 entered waiting room.
JILL is now serving BACK 15
Producer FRONT is finished.
Producer BACK is finished.
Clerk HERMAN is finished.
Clerk JILL is finished.