I would like to know if the following method is correct or not.
I've producer and consumer thread that work on a common BlockingQueue.
The producer is a sniffer thread so it will stop automatically,but fot the consumer i think to terminate with a loop on status (alive/dead) of producer thread. Any suggestions? Thanks
-)From the Main thread:
ArrayBlockingQueue<PcapPacket> queue = new ArrayBlockingQueue<>();
Producer p = new Producer(queue);
Thread t1 =new Thread(p);
t1.start();
Consumer c = new Consumer(queue,t1);
new Thread(c).start();
-)Producer
public void run() {
public void nextPacket(PcapPacket packet, String user) {
try {
queue.put(packet);
} catch (InterruptedException ex) {
}
-) Consumer
public void run() {
while(producer.isAlive()){
try {
//Thread.sleep(50);
packet=queue.take();
Polling producer's status is sub-optimal.
Preferred approach is to make producer, during producer exit, put some 'poison pill' into queue, and for consumer to end it's loop as soon as it have received that pill:
class Producer implements Runnable {
static final Object TIME_TO_STOP = new Object();
private final BlockingQueue<Object> q;
Producer(BlockingQueue<Object> q) {
this.q = q;
}
#Override
public void run() {
try {
while (true) {
q.put(readNextPacket());
}
} finally {
// exception happened
try {
q.put(TIME_TO_STOP);
} catch (InterruptedException e) {
// somehow log failure to stop properly
}
}
}
}
class Consumer implements Runnable {
private final BlockingQueue<Object> q;
Consumer(BlockingQueue<Object> q) {
this.q = q;
}
#Override
public void run() {
while (true) {
Object packet = q.take();
if (packet == Producer.TIME_TO_STOP) {
break;
}
// process packet
}
}
}
Related
I'm doing a desktop application and I'm performing a heavy task in background. I want a progress bar to be updated. My program works and I can see the progress bar here isn't my problem. My problem is that I use 2 tasks that I run in 2 thread in order to make both the update of the progress bar and the heavy task. My question is : Is there a better way to do in oder to avoid the error "Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5".
Of course I already check on Internet and I always find : better use Platform.runLater. Ok but in both new thread I need attribute of my class, eg I can't access for example "this.myAttribute" when I use Platform.runLater((new Runnable()...)). Is RunLater the solution and I can't see it ?
Here is a bunch of code, the method setConnection is called in JavaFX thread, and I create 2 other. One for progressbar, the other for my task :
#FXML
private void setConnection() {
try {
this.onOffButton.setSelected(false);
if (!this.hubModel.isConnected()) {
this.progressBar.progressProperty().unbind();
#SuppressWarnings("unchecked")
OperationTask progressBarOperationTask = new OperationTask(this) {
#Override
public Void call() {
HubController hubController = (HubController) this.getHubController();
hubController.getProgressBar().setVisible(true);
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(25);
} catch (InterruptedException e) {
Thread.interrupted();
break;
}
updateProgress(i + 1, 100);
}
hubController.getProgressBar().setVisible(false);
return null;
}
};
this.progressBar.progressProperty().bind(progressBarOperationTask.progressProperty());
Thread timeThread = new Thread(progressBarOperationTask);
timeThread.setDaemon(true);
timeThread.start();
}
#SuppressWarnings("unchecked")
OperationTask connectionOperationTask = new OperationTask(this) {
#Override
protected Object call() throws Exception {
HubController hubController = (HubController) this.getHubController();
if (hubController.getUserID().getText().equals("") || hubController.getUserPW().getText().equals("")) {
hubController.getCommentBottom().setText("Please enter a user name and a password.");
hubController.getOnOffButton().setSelected(false);
} else {
hubController.getHubModel().setIdUser(hubController.getUserID().getText());
hubController.getHubModel().setPwUser(hubController.getUserPW().getText());
String comment = hubController.getHubModel().setConnection();
if (!comment.equals("Connection established.")) {
hubController.getOnOffButton().setSelected(false);
}
if (hubController.getHubModel().isConnected()) {
hubController.getConnectionStatus().setText("Connected");
hubController.getConnectionStatus().setStyle("-fx-font-weight: bold");
String commentProject = hubController.getHubModel().getAllProjects();
if (commentProject.equals("")) {
TextFields.bindAutoCompletion(hubController.getCloneAndMoveController().getNewProjectNameTextField(), hubController.getHubModel().getProjectsList());
} else {
comment = commentProject;
}
hubController.getOnOffButton().setSelected(true);
} else {
hubController.getConnectionStatus().setText("Not connected");
hubController.getConnectionStatus().setStyle("-fx-font-weight: regular");
}
hubController.getCommentBottom().setText(comment);
}
return null;
}
};
Thread connectionThread = new Thread(connectionOperationTask);
connectionThread.setDaemon(true);
connectionThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}
Moreover if you see something that could be improved, I would appreciate (I'm new with java)
Thank you.
You can access your object from Platform.runLater(). New Runnable which you create for it has access to this instance of your object. See in an example:
private String myAttribute = "hello";
#Override
public void randomMethod() {
//...
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println(myAttribute);
}
});
}
I am trying to learn basic concept of Multi Threading.
Why my ping pong program prints only Ping0 & Pong0, Why notify() does not start the Ping Thread which is in Wait state?
public class PingPong implements Runnable {
String word;
public PingPong(String word) {
this.word = word;
}
public void run() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
System.out.println(word + i);
try {
wait();
notifyAll();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
public static void main(String[] args) {
Runnable p1 = new PingPong("ping");
Thread t1 = new Thread(p1);
t1.start();
Runnable p2 = new PingPong("pong");
Thread t2 = new Thread(p2);
t2.start();
}
}
Output
ping0
pong0
I tried removing wait() and it's printing ping pong till the end of loop. but is this guaranteed that it will print in sequence?
Why wait() followed by notify() does not ask the ping1 thread to start execution?
If you see the jstack, you can see thread-0 and thread-1 are waiting for different lock. That's because your p1 and p2 are different objects, so when you use synchronized (this), they are not competing for the same lock, so notify this way won't work. try use another object as the lock.
wait need to run after notify. As when both threads go into waiting stat, no other threads can notify them.
try this code:
String word;
Object a;
public PingPong(String word, Object a) {
this.word = word;
this.a = a;
}
public void run() {
synchronized (a) {
for (int i = 0; i < 10; i++) {
System.out.println(word + i);
try {
a.notifyAll();
a.wait();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Object a = new Object();
Runnable p1 = new PingPong("ping", a);
Thread t1 = new Thread(p1);
t1.start();
Runnable p2 = new PingPong("pong", a);
Thread t2 = new Thread(p2);
t2.start();
}
Here is a similar solution using Thread Pool Executors:
public class PingPong implements Runnable {
String word;
Lock lock;
public PingPong(String word, Lock lock) {
this.word = word;
this.lock = lock;
}
#Override
public void run() {
while(true){
System.out.println("Received : " + word);
lock.notifyAll();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ExecutorService ex = Executors.newFixedThreadPool(2);
Lock lock = new ReentrantLock();
while(true){
ex.submit(new PingPong("ping", lock));
ex.submit(new PingPong("pong", lock));
}
}
}
Below solution based on:
Java internal API
order of execution
public class Test {
public static void main(String[] args) {
SynchronousQueue<String> queue = new SynchronousQueue<>();
Thread ping = new Thread(new Task(queue, "ping", "ping"));
ping.setName("ping thread");
ping.start();
Thread pong = new Thread(new Task(queue, "pong", "ping"));
pong.setName("pong thread");
pong.start();
}
private static class Task implements Runnable {
private SynchronousQueue<String> queue;
private String command;
private String step;
Task(SynchronousQueue<String> queue, String command, String step) {
this.queue = queue;
this.command = command;
this.step = step;
}
#Override
public void run() {
try {
if (command.equals(step)) {
doCommandAndWaitRepeatedly();
} else {
waitAndDoCommandRepeatedly();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void doCommandAndWaitRepeatedly() throws InterruptedException {
while (true) {
queue.offer(command, 1, TimeUnit.SECONDS);
Thread.sleep(500);
System.out.println(Thread.currentThread().getName() + ":" + queue.poll(1, TimeUnit.SECONDS));
}
}
private void waitAndDoCommandRepeatedly() throws InterruptedException {
while (true) {
System.out.println(Thread.currentThread().getName() + ":" + queue.poll(1, TimeUnit.SECONDS));
Thread.sleep(500);
queue.offer(command, 1, TimeUnit.SECONDS);
}
}
}
}
class Ping extends Thread
{
public void run()
{
for(int i=1;i<=5;i++)
{
System.out.println("PING");
try{
sleep(2000);
} catch(Exception e){}
}
}
}
class Pong extends Thread
{
public void run()
{
for (int i=1;i<=5;i++)
{
System.out.println("PONG");
try{
sleep(2000);
} catch(Exception e){}
}
}
}
public class PingPong
{
public static void main(String... args) throws Exception
{
Ping p1=new Ping();
Pong p2=new Pong();
p1.start();
Thread.sleep(1000); //super important for proper sequence
p2.start();
p1.join();
}
}
I am new to JavaFx/Concurrency so I read the tutorial over at Concurrency in JavaFX but I am still a little confused about the implementation of background threads in a JavaFX Gui.
I'm trying to write a small GUI that interfaces with some serial devices (using JSSC-2.8) and that updates the GUI based on the responses from those devices. But, there's a lag between when the message is written and when the device responds, and using Thread.sleep() for an arbitrary amount of time wasn't a reliable way for me program it. So instead I want to use wait() and notify() methods from the concurrency package (with all the appropriate synchronizations), but I am not sure how to implement it. What I initially did is create another Thread, inside the Task, that would write the messages and wait for the responses, and using some bindings, would update the GUI. I've included my code at the end. Here is a short form of the pseudocode I am trying to implement:
start Task:
connect to serial devices
synchronized loop:
send messages
wait() for event to fire
notify()
But what's been happening is, as soon as I call the wait(), the entire application idles and then when notify() is called (after the response fires and event), it doesn't continue where it left off in the recipe() loop, or the startTdk() loop for that matter, it's just idle. Have I implements the threads wrong? When I am calling the wait(), is it a possibility that I cause the EventDispatch or JavaFX Application Thread to pause?
I hope the question is clear, if there are any clarifications needed I can update the post.
public class OmicronRecipe extends Service<String> implements Runnable{
private final String SEPERATOR=";";
private final Tdk tdk;
private final Pvci pvci;
private final SimpleStringProperty data = new SimpleStringProperty("");
private final Float MAX_V = 26.0f,UHV=1e-8f;
private boolean isTdkOn=false, isPvciOn=false;
private String power;
private Float temp,press,maxT, setT;
private int diffMaxT,diffP,diffPow, diffT, index=0;
public OmicronRecipe(){
tdk = new Tdk("COM4");
pvci = new Pvci("COM5");
}
private synchronized void recipe(){
while (true){
try {
sendMessages();
data.set(power+SEPERATOR+temp+SEPERATOR+press);
calcDiffs();
if (diffPow < 0){
if(diffMaxT < 0){
if(diffT < 0){
if (diffP < 0){
if(!rampPow()){
//Max Power reached
}
}else{
//Wait for pressure drop
}
}
}else{
//Wait until quit
}
}else{
//Max power reached
}
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(OmicronRecipe.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private synchronized boolean rampPow(){
boolean isRamped=false;
Float setPow = tdk.getSetPow(index), curPow;
setT = tdk.getSetT(index);
curPow = Float.parseFloat(power);
if(curPow.compareTo(setPow) < 0){
do{
curPow += 0.1f;
tdk.sendMessage("PV "+curPow+"\r");
try {
wait();
} catch (InterruptedException ex) {
Logger.getLogger(OmicronRecipe.class.getName()).log(Level.SEVERE, null, ex);
}
curPow = Float.parseFloat(power);
}while(curPow.compareTo(setPow) < 0);
index++;
isRamped=true;
}
return isRamped;
}
public synchronized boolean connect(){
if(!isTdkOn && !isPvciOn){
isTdkOn = tdk.connect();
isPvciOn = pvci.connect();
}
return isTdkOn && isPvciOn;
}
public synchronized boolean disconnect(){
if(tdk!=null && pvci !=null){
isTdkOn = tdk.disconnect();
isPvciOn = pvci.disconnect();
}
return !isTdkOn && !isPvciOn;
}
public synchronized StringProperty getData(){
return data;
}
public void setMaxT(Float maxT){
this.maxT = maxT;
}
private synchronized void calcDiffs(){
Float pow = Float.parseFloat(power);
diffPow = pow.compareTo(MAX_V);
diffMaxT = temp.compareTo(maxT);
diffT = temp.compareTo(100f);
diffP = press.compareTo(UHV);
}
private synchronized void setListeners(){
tdk.getLine().addListener((ov,t, t1)-> {
synchronized (this){
System.out.println("New Power: "+t1);
power = t1;
this.notify();
}
});
pvci.getLine().addListener((ov,t,t1) ->{
synchronized (this){
String[] msg = t1.split(SEPERATOR);
if(msg.length == 2){
switch(msg[0]){
case "temperature":
System.out.println("Temperaute");
temp = Float.parseFloat(msg[1]);
break;
case "pressure":
System.out.println("Pressure");
press = Float.parseFloat(msg[1]);
break;
default:
System.out.println("Nothing; Something went wrong");
break;
}
}
this.notify();
}
});
}
private synchronized void sendMessages(){
try {
tdk.sendMessage("PV?\r");
this.wait();
pvci.sendMessage("temperature");
this.wait();
pvci.sendMessage("pressure");
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(OmicronRecipe.class.getName()).log(Level.SEVERE, null, ex);
}
}
private synchronized boolean startTdk(){
boolean isOut=false;
if(isTdkOn){
try {
tdk.sendMessage("ADR 06\r");
this.wait();
System.out.println("Power: "+power);
if(power.equals("OK")){
tdk.sendMessage("OUT?\r");
this.wait();
if(power.equals("OFF")){
tdk.sendMessage("OUT ON\r");
this.wait();
isOut = power.equals("ON");
}
else{
isOut = power.equals("ON");
}
}
} catch (InterruptedException ex) {
Logger.getLogger(OmicronRecipe.class.getName()).log(Level.SEVERE, null, ex);
}
}
return isOut;
}
#Override
protected Task<String> createTask() {
return new Task<String>() {
#Override
protected String call() throws IOException{
new Thread(new OmicronRecipe()).start();
return "";
}
};
}
#Override
public void run() {
if (connect()){
setListeners();
if(startTdk()){
recipe();
}
}
}
}
I won't include the Pvci class, because it just a copy of the Tdk class but with specific message sequences to talk with that machine.
public class Tdk {
private SerialPort tdkPort;
private final String portName;
private StringBuilder sb = new StringBuilder("");;
private final StringProperty line = new SimpleStringProperty("");
private final HashMap<Float,Float> calibMap;
private ArrayList<Float> list ;
private boolean isEnd=false;
public Tdk(String portName){
this.portName = portName;
System.out.println("TDK at "+portName);
calibMap = new HashMap();
setMap();
}
public synchronized boolean connect(){
tdkPort = new SerialPort(portName);
try {
System.out.println("Connecting");
tdkPort.openPort();
tdkPort.setParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
tdkPort.setEventsMask(SerialPort.MASK_RXCHAR);
tdkPort.addEventListener(event -> {
if(event.isRXCHAR()){
if(event.getPortName().equals(portName)){
try {
if(!isEnd){
int[] str = tdkPort.readIntArray();
if(str!=null)
hexToString(str);
}
if(isEnd){
System.out.println("Here: "+sb.toString());
isEnd=false;
String d = sb.toString();
sb = new StringBuilder("");
line.setValue(d);
}
} catch (SerialPortException e) {
Logger.getLogger(Tdk.class.getName()).log(Level.SEVERE, null, e);
}
}
}
});
} catch (SerialPortException e) {
Logger.getLogger(Tdk.class.getName()).log(Level.SEVERE, null, e);
}
return tdkPort !=null && tdkPort.isOpened();
}
public synchronized boolean disconnect(){
if(tdkPort!=null) {
try {
tdkPort.removeEventListener();
if (tdkPort.isOpened())
tdkPort.closePort();
} catch (SerialPortException e) {
Logger.getLogger(Tdk.class.getName()).log(Level.SEVERE, null, e);
}
System.out.println("Disconnecting");
}
return tdkPort.isOpened();
}
public synchronized void sendMessage(String message){
try {
tdkPort.writeBytes(message.getBytes());
} catch (SerialPortException e) {
Logger.getLogger(Tdk.class.getName()).log(Level.SEVERE, null, e);
}
}
private void setMap(){
calibMap.put(1.0f, 25.0f);
calibMap.put(7.0f, 125.0f);
calibMap.put(9.8f, 220.0f);
list = new ArrayList(calibMap.keySet());
}
public Float getSetPow(int index){
return list.get(index);
}
public Float getSetT(int index){
return calibMap.get(list.get(index));
}
public synchronized StringProperty getLine(){
return line;
}
private synchronized void hexToString(int[] hexVal){
for(int i : hexVal){
if(i != 13){
sb.append((char)i);
}else{
isEnd=true;
}
}
System.out.println("Turning: "+Arrays.toString(hexVal)+" to String: "+sb.toString()+" End: "+isEnd);
}
Freeze
Your UI freezes most probably because you are waiting on the FX Apllication Thread, to solve this there are different approaches:
JavaFX Application Thread
You can delegate some work to the FX Application Thread, therefore see Platform.runLater
Not everything can be run on this thread, but for example, in your DeviceController, you can wait until the message appears and then call Platform.runLater() and update the field (you should therefor oc hand the field over to the controller).
DataBinding
What you are describing can also be realised with DataBinding.
With this you could define a SimpleStringProperty, which is bound to your UI Label (.bind() Method). If the controller must fire its message you can set the StringProperty and the UI will update itself.
The scenario you described could be used like this:
start Task:
connect to serial devices
synchronized loop:
send messages
wait() for event to fire
**updateDate the DataBounded fields**
We are taught that, Concurrency notify/wait
Concurrency on level wait()/notify() is very low level. You should try to work with higher level synchronisation methods or helpers (where people have already solved your problems :))
I have a TableView associated with some data, and once i hit a run button i perform some processing on that data. Each row of data is handled in a seperate thread, and while those threads are running i want a ProgressInducator to replace the table within its vbox.
In the attached code:
If I stop where is says "WORKS IF STOP HERE" - table is replaced with pi.
If I continue waiting for the threads to join - no replacing.
What am I missing?
runButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(final ActionEvent e) {
List<Thread> threadList = new ArrayList<Thread>();
int threadCounter = 0;
final ProgressIndicator pi = new ProgressIndicator(threadCounter);
vbox.getChildren().clear();
vbox.getChildren().addAll(pi);
for (ProductInTable product : data) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try
{
product.calculate();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
threadList.add(thread);
thread.start();
}
int x = threadList.size();
/** WORKS IF STOP HERE **/
// wait for all threads to end
for (Thread t : threadList) {
try {
t.join();
threadCounter++;
pi.setProgress(threadCounter / x);
} catch (InterruptedException interE) {
interE.printStackTrace();
}
}
/** DOESNT WORKS IF STOP HERE **/
Thread.join() blocks execution until the thread is completed. Since you are calling this on the FX Application Thread, you block that thread until all your worker threads finish. This means the UI is unable to update until those threads are complete.
A better approach is probably to represent each computation with a task, and update a counter of complete tasks back on the FX Application Thread using setOnSucceeded. Something like:
runButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(final ActionEvent e) {
final ProgressIndicator pi = new ProgressIndicator(threadCounter);
vbox.getChildren().clear();
vbox.getChildren().addAll(pi);
final int numTasks = data.size();
// only access from FX Application thread:
final IntegerProperty completedTaskCount = new SimpleIntegerProperty(0);
pi.progressProperty().bind(completedTaskCount.divide(1.0*numTasks));
completedTaskCount.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> obs, Number oldValue, Number newValue) {
if (newValue.intValue() >= numTasks) {
// hide progress indicator and show table..
}
}
});
for (final ProductInTable product : data) {
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
try
{
product.calculate();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return null ;
}
});
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
completedTaskCount.set(completedTaskCount.get()+1);
}
});
new Thread(task).start();
}
}
});
If you potentially have a large number of items here, you should use some kind of ExecutorService instead to avoid creating too many threads:
ExecutorService exec = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors()); // for example...
and then replace
new Thread(task).start();
with
exec.submit(task);
I have been facing this problem for many days, Please help me out. I am implementing producer-consumer example using thread synchronization. I have made some twist in this traditional program. Instead of using only one queue object, i have used two Queue objects. But program is not working.. (PS- I know i can make this program work by using only one object of queue, But what if i want to use two queue objects ?? )
class Queue {
static int value;
static boolean valueSet = false;
public static final Object obj;
static {
obj = new Object();
}
void push() {
synchronized(Queue.obj) {
while( Queue.valueSet ) {
try {
Thread.sleep(1000);
}catch(Exception e) {}
}
System.out.print("\n\n Push:- " + (++(Queue.value)));
Queue.valueSet = true;
return;
}
}
void pop() {
synchronized(Queue.obj) {
while(!(Queue.valueSet)) {
try {
Thread.sleep(1000);
}catch(Exception e) {}
}
System.out.print("\n\n Pop:- " + Queue.value);
Queue.valueSet = false;
return;
}
}
}
class Producer implements Runnable {
Queue Q;
Thread P;
Producer(Queue Q) {
this.Q = Q;
P = new Thread(this);
P.start();
}
public void run() {
while(true) {
Q.push();
}
}
}
class Consumer implements Runnable {
Queue Q;
Thread C;
Consumer(Queue Q) {
this.Q = Q;
C = new Thread(this);
C.start();
}
public void run() {
while(true) {
Q.pop();
}
}
}
public class TestQueue {
public static void main(String[] args) {
Queue Q1 = new Queue();
Queue Q2 = new Queue();
Object obj = new Object();
Producer p = new Producer(Q1);
Consumer c = new Consumer(Q2);
}
}
I got the answer. My misconception was wait,notify and notifyall methods are of thread class. So i was invoking them on thread object.
Solution is to just invoke wait and notify method on shared static object other than thread.
Answer:-
class Queue {
static int value;
static boolean valueSet = false;
public static final Object obj;
static {
obj = new Object();
}
void push() {
synchronized(Queue.obj) {
while( Queue.valueSet ) {
try {
Queue.obj.wait();
Thread.sleep(1000);
}catch(Exception e) {
e.printStackTrace();
}
}
System.out.print("\n\n Push:- " + (++(Queue.value)));
Queue.valueSet = true;
Queue.obj.notify();
}
}
void pop() {
synchronized(Queue.obj) {
while(!(Queue.valueSet)) {
try {
Queue.obj.wait();
Thread.sleep(1000);
}catch(Exception e) {
e.printStackTrace();
}
}
System.out.print("\n\n Pop:- " + Queue.value);
Queue.valueSet = false;
Queue.obj.notify();
}
}
}
class Producer implements Runnable {
Queue Q;
Thread P;
Producer(Queue Q) {
this.Q = Q;
P = new Thread(this);
P.start();
}
public void run() {
while(true) {
Q.push();
}
}
}
class Consumer implements Runnable {
Queue Q;
Thread C;
Consumer(Queue Q) {
this.Q = Q;
C = new Thread(this);
C.start();
}
public void run() {
while(true) {
Q.pop();
}
}
}
public class TestQueue {
public static void main(String[] args) {
Queue Q1 = new Queue();
Queue Q2 = new Queue();
Producer p = new Producer(Q1);
Consumer c = new Consumer(Q2);
}
}