I have this exercise, a kind of hospital simulation in which I have to control the accesses to each singular room. Doctors can enter the room one at the time, and can enter only if no visitors are in. A visitor, instead, can only access the room if no doctors are in it and a max of 4 more visitors are in. Here's my code:
public class Room {
public Room(){
}
public synchronized void friendVisit() throws InterruptedException{
if(visitors>4 || doctors>0)
wait();
visitors++;
}
public synchronized void exitFriend(){
visitors--;
notify();
}
public synchronized void doctorVisit() throws InterruptedException{
if(doctors>0 || visitors>0)
wait();
doctors++;
}
public synchronized void exitDoctor(){
--doctors;
notify();
}
public int getVisitors(){
return visitors;
}
public int getDoctors(){
return doctors;
}
int visitors=0; //number of visitors in the room
int doctors=0; //number of doctors in the room
Doctors and Visitors(the class it's called Friend) are threads
public class Friend extends Thread{
public Friend(Room room_reference){
room=room_reference;
}
public void run(){
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
room.friendVisit();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
room.exitFriend();
}
private Room room; //reference to the room
Here's the doctor thread:
public class Doctor extends Thread{
public Doctor(Room room_reference){
room=room_reference;
}
public void run(){
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
room.doctorVisit();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
room.exitDoctor();
}
private Room room; //reference to the room
Here's a Display thread to keep trace of the number of visitors and doctors:
public class Display extends Thread{
public Display(Room room_reference){
room=room_reference;
}
public void run(){
while(true)
{
try {
sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("The room contains "+room.getDoctors()+
" doctors and "+room.getVisitors()+" visitors.");
}
}
private Room room;
And here's my main:
public class Demo {
public static void main(String[]args){
Room room=new Room();
Friend friend=new Friend(room);
Doctor doctor=new Doctor(room);
Display display=new Display(room);
display.start();
while(true){
if(new Random().nextBoolean()==true){
friend=new Friend(room);
friend.start();
}
if(new Random().nextInt(5)==3){
doctor=new Doctor(room);
doctor.start();
}
}
}
The problem is that more than one doctor can access the room and I don't understand why, since the methods in the Room class work for the Visitors. Thanks in advance.
I think one of your mistakes is assuming that wait() will return only when the condition above it is satisfied:
if(doctors>0 || visitors>0)
wait();
You may return from this call to wait() with the condition in your if statement false. Perhaps try a while loop:
while (doctors>0 || visitors>0) {
wait();
}
(adding brackets, of course, because you know a lack of brackets is evillll.....)
There may be other problems - I've not yet fired up your code.
Related
I write a Java program to solve Producer Consumer problem in Multi-Threads. But it can not work correctly.
The program:
public class ConsumerAndProducer {
static int products = 0;
static int capacity = 10;
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
}
static class Consumer implements Runnable{
public void consume() {
synchronized (ConsumerAndProducer.class){
if(products <= 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
products--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Consumer, remain:" + products);
if(products == 9){
notify();
}
}
}
#Override
public void run() {
while(true){
consume();
}
}
}
static class Producer implements Runnable{
public void produce() {
synchronized (ConsumerAndProducer.class){
if(products == capacity){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
products++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Producer, remain:" + products);
if(products == 1){
notify();
}
}
}
#Override
public void run() {
while(true){
produce();
}
}
}
And the errors:
Producer, remain:1
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at zhousai.ConsumerAndProducer$Producer.produce(ConsumerAndProducer.java:69)
at zhousai.ConsumerAndProducer$Producer.run(ConsumerAndProducer.java:77)
at java.lang.Thread.run(Thread.java:748)
Consumer, remain:0
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at zhousai.ConsumerAndProducer$Consumer.consume(ConsumerAndProducer.java:22)
at zhousai.ConsumerAndProducer$Consumer.run(ConsumerAndProducer.java:43)
at java.lang.Thread.run(Thread.java:748)
When I ran your code, I got the following error:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
The line of your code throwing that exception is the call to method wait().
You are calling method wait() of class Producer but you are synchronizing on ConsumerAndProducer.class. The wait() method must be called on the object that you are synchronizing on, because that object owns the lock and you must call wait() on the object that owns the lock. Hence the error message: current thread not owner.
The simplest solution is to change your code such that you call ConsumerAndProducer.class.wait() rather than just wait().
Here is your code with my suggested fix:
public class ConsumerAndProducer {
static int products = 0;
static int capacity = 10;
public static void main(String[] args) {
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
}
static class Consumer implements Runnable {
public void consume() {
synchronized (ConsumerAndProducer.class){
if (products <= 0) {
try {
ConsumerAndProducer.class.wait(); // change here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
products--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Consumer, remain:" + products);
if(products == 9){
ConsumerAndProducer.class.notify(); // change here
}
}
}
#Override
public void run() {
while(true){
consume();
}
}
}
static class Producer implements Runnable{
public void produce() {
synchronized (ConsumerAndProducer.class){
if (products == capacity) {
try {
ConsumerAndProducer.class.wait(); // change here
} catch (InterruptedException e) {
e.printStackTrace();
}
}
products++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Producer, remain:" + products);
if(products == 1){
ConsumerAndProducer.class.notify(); // change here
}
}
}
#Override
public void run() {
while(true){
produce();
}
}
}
}
I'm trying to suspend (or pause) the active thread using wait() I have implemented this in my code already but when I run the code it doesn't output anything, I think it's because when it runs it starts on "suspend" would appreciate any help solving this issue. Here is the relevant code and a link with everything just in case.
GreenhouseControls.java
public class GreenhouseControls extends Controller implements Serializable {
...
private Boolean suspend = false;
...
public void SuspendEvent() {
suspend = true;
}
public void ResumeEvent() {
suspend = false;
}
public Boolean getSuspend() {
return suspend;
}
...
}
Event.java
public abstract class Event implements Runnable {
...
private boolean suspend;
...
public synchronized void isSuspended() {
suspend = greenhouseControls.getSuspend();
notifyAll();
}
public void run() {
try {
while (suspend = true) {
try {
synchronized(this) {
wait();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread.sleep(delayTime);
}
catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.action();
}
catch (GreenhouseControls.ControllerException e) {
e.printStackTrace();
}
}
...
}
FansOff.java: there are other classes like this one each very similar to each other and they are the ones actually producing the output
public class FansOff extends Event {
...
public void run() {
try {
boolean suspend = false;
while (suspend = true) {
try {
synchronized(this) {
wait();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread.sleep(delayTime);
}
catch (InterruptedException e) {
e.printStackTrace();
}
try {
this.action();
System.out.println(this.toString());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Full code: here.
Thanks in advance.
I happen to have a problem with some attempts at reading the same variable in socket multi-threading, not being able to share it among threads.
It works as an app where an employer assigns work to an employee. Through his interface the employer can add and assignment to an ArrayList inside a class named ListadoPedidos.
When the employer's ServerSocket accepts an employee Socket, it starts a TCP connection and launches the following thread:
public class HiloServer implements Runnable{
private ListadoPedidos peds=new ListadoPedidos();
private ListadoOperarios operarios=new ListadoOperarios();
private ListadoSockets sockets=new ListadoSockets();
private SocketServer s;
public HiloServer(SocketServer sock, JFrame frame, ListadoPedidos pedidos) {
s=sock;
peds=pedidos;
}
/* (non-Javadoc)
* #see java.lang.Runnable#run()
*/
#Override
public void run() {
boolean agregar;
Socket nuevo;
try {
while(true) {
// ACEPTA OPERARIOS QUE DESEEN CONECTARSE
s.aceptar();
nuevo=s.getSocket();
sockets.addSocket(nuevo);
new NuevoCliente();
HiloDatos hd=new HiloDatos(s, nuevo,operarios,peds,sockets);
Thread t=new Thread(hd);
t.start();
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
*note that I send the object where the assigments added are stored.
Then it starts another thread that will work as a sort of "validation" for a number the employee's have to insert and send through his Swing interface to truly enter the system. This thread is generated everytime a new socket employee makes a TCP connection to the ServerSocket employer. It goes like:
public class HiloDatos implements Runnable {
private int n;
private Socket cliente;
private SocketServer server;
private int opRecibido;
private ListadoOperarios ops;
private ListadoPedidos peds;
private ListadoSockets socks;
public HiloDatos(SocketServer ss, Socket nuevo, ListadoOperarios operarios, ListadoPedidos pedidos, ListadoSockets sockets) {
cliente=nuevo;
server=ss;
ops=operarios;
peds=pedidos;
socks=sockets;
}
#Override
public void run() {
server.setSocket(cliente);
boolean agregar, aceptado=false;
try {
do {
// RECIBE EL NRO OPERARIO Y VERIFICA SU EXISTENCIA
agregar=true;
opRecibido=Integer.parseInt(server.recibir());
for(int c=0;c<ops.getOperarios().size();c++) {
if (opRecibido==ops.getOperarios().get(c)) {
new ErrorRepetido();
agregar=false;break;
}
}
if (agregar==true) {
ops.addOperarios(opRecibido);
server.enviar("Si");
aceptado=true;
}
}while(aceptado==false);
HiloPedidos hp=new HiloPedidos(server,opRecibido,ops,peds,socks);
Thread t=new Thread(hp);
t.start();
}catch (NumberFormatException e) {
new ErrorDatos();
} catch (ConnectException e) {
new ErrorConexion();
} catch (SocketException e) {
try {
socks.getSockets().remove(socks.getSockets().indexOf(cliente));
cliente.close();
} catch (IOException e1) {
new ErrorFlujo();
}
new WarnSocket();
} catch (IOException e) {
try {
socks.getSockets().remove(socks.getSockets().indexOf(cliente));
cliente.close();
} catch (IOException e1) {
new ErrorFlujo();
}
new WarnFlujo();
}
}
}
And lastly it launches yet another Thread that looks for that same validation number from the thread above in the ArrayList of assignments ("pedidos" of class ListadoPedidos) i kept passing from thread to thread, and if it finds a "new" one, it should send it to the connected socket:
public class HiloPedidos implements Runnable {
private Pedido ped;
private SocketServer server;
private int op;
private ListadoOperarios ops;
private ListadoPedidos peds;
private ListadoSockets socks;
public HiloPedidos(SocketServer ss, int opRecibido, ListadoOperarios operarios, ListadoPedidos pedidos, ListadoSockets sockets) {
server=ss;
opRecibido=op;
ops=operarios;
peds=pedidos;
socks=sockets;
}
#Override
public void run() {
int cambio=0, nuevo;
Pedido pedRecibido;
try {
while(true) {
// ENVÍA PEDIDOS
nuevo=peds.Contar(op);
if(nuevo==cambio) {
cambio=peds.Contar(op);
pedRecibido=peds.TraerNuevo(op, cambio);
server.enviarObjeto(pedRecibido);
}
}}
catch (NumberFormatException e) {
new ErrorDatos();
} catch (ConnectException e) {
new ErrorConexion();
} catch (SocketException e) {
try {
socks.getSockets().remove(socks.getSockets().indexOf(server.getSocket()));
server.getSocket().close();
} catch (IOException e1) {
new ErrorFlujo();
}
new WarnSocket();
} catch (IOException e) {
try {
socks.getSockets().remove(socks.getSockets().indexOf(server.getSocket()));
server.getSocket().close();
} catch (IOException e1) {
new ErrorFlujo();
}
new WarnFlujo();
}
}
}
Problem is that the last thread can't really notice a change in the list, as i debugged it and never reached the breakpoint inside the condition of sending the assignment. The class ListadoPedidos goes like this:
public class ListadoPedidos {
private static volatile ArrayList<Pedido> pedidos=new ArrayList<>();
public ListadoPedidos() {
}
public ArrayList<Pedido> getPedidos() {
return pedidos;
}
public synchronized void addPedidos(Pedido pedido) {
pedidos.add(pedido);
}
public int Contar(int o) {
int n=0;
for (Pedido p: pedidos) {
if (p.getNro_operario()==o) {
n++;
}
}
return n;
}
public Pedido TraerNuevo(int o, int c) {
int n=0;
Pedido nuevo = new Pedido();
for (Pedido p: pedidos) {
if (p.getNro_operario()==o) {
n++;
}
if (n==c) {
nuevo=p;break;
}
}
return nuevo;
}
}
Contar is the one that counts for an assignment with the value nrooperario same as the value it brings from the thread, and TraerNuevo brings the assignment to be sended (never reached this method).
I tried declaring the ArrayList as volatile and all but nothing works. Mind that even if i use socket connections, the problem has more to do with shared varaible not being able to update between threads. Any help will be appreciated.
Try this, basically, synchronize access.
public class ListadoPedidos {
private static volatile ArrayList<Pedido> pedidos=new ArrayList<>();
public ListadoPedidos() {
}
/**
* Here DO NOT return the arrayList. The underlying implementation is not threadsafe
*/
// public ArrayList<Pedido> getPedidos() {
// return pedidos;
// }
public synchronized void addPedidos(Pedido pedido) {
pedidos.add(pedido);
}
public synchronized int Contar(int o) {
int n=0;
for (Pedido p: pedidos) {
if (p.getNro_operario()==o) {
n++;
}
}
return n;
}
public synchronized Pedido TraerNuevo(int o, int c) {
int n=0;
Pedido nuevo = new Pedido();
for (Pedido p: pedidos) {
if (p.getNro_operario()==o) {
n++;
}
if (n==c) {
nuevo=p;break;
}
}
return nuevo;
}
}
The amount of code you have given us makes it difficult to answer your question. To be honest, the Spanish does not help either. But I can give you some general advice.
Let us start with the question. What exactly is the question? From what I can understand, it comes down to: "how can two threads read the same variable?"
Even if that is not the question, try to make the question as clear as possible for yourself.
Then start with a new test-project separate from the project you are working on. Write the minimal amount of code that you think should work. If it does not work, write even less code that does work (e.g. use static variables to make things even more simple). Go back and forth until you have code that can answer your question. If you cannot get it to work, step back and think about assumptions that you made that might not be true.
If you still cannot figure it out, come back here with the minimal amount of code that you think should work and a clear question.
This method of "trying it with minimal code in a test-project" is something I still use after years of programming to solve problems. When I solve a problem this way, I usually learn something new and often I discover that I made an assumption that did not hold true.
I am learning multithreading.
I tried to implement producer consumer problem in Java.Its working fine.
But if i remove notify call the program goes into a deadlock state.Why?
Its going on deadlock when size of queue becomes 0.Ideally when size becomes 0,wait should be called inside consumer and producer should started working.
import java.io.*;
import java.util.*;
class Consumer implements Runnable{
Queue<Integer> q;
int n;
public void run() {
while(true){
synchronized (q) {
while(q.size()==0){
try {
System.out.println("q.size="+q.size());
q.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("item consumed="+q.poll());
q.notify();
try {
Thread.sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Consumer(Queue<Integer> queue,int n){
q=queue;
this.n=n;
}
}
class Producer implements Runnable{
Queue<Integer> q;
int n;
public void run() {
int x=1;
while(true){
synchronized (q) {
while(q.size()==n){
try {
q.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("item produced="+x+" q.size="+q.size());
q.add(x++);
q.notify();
try {
Thread.sleep((int)(Math.random() * 100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Producer(Queue<Integer> queue,int n){
q=queue;
this.n=n;
}
}
public class App
{
public static void main( String[] args ) throws InterruptedException
{
int n=100;
Queue<Integer> q=new LinkedList<Integer>();
Thread t1=new Thread(new Producer(q, n));
Thread t2=new Thread(new Consumer(q, n));
t1.start();
t2.start();
t1.join();
t2.join();
}
}
you required notify because when one thread is on wait state because queue is empty or full come to running state if some other thread notify after putting if queue is empty and taking queue is full.
put q.wait(10); so your code will not go on deadlock because after time it will check while loop condition.
It is always best practice to use notify in above usecase
let's say i have 3 classes:
1. Storage which contains just one integer.
2. Counter which contains a thread inside who's responsible for counting (0,1,..,k) and stores each iteration of the loop index in Storage class.
3.Printer which contains a thread who's responsible for reading the value in class Storage and print it.
now i have to create a main class which creates these 3 objects runs the threads of Counter and Printer , and everynumber from(0,1,..,k) has to be printed just once and in the right order.
how do i synchronize the access to my Storage class so first i put a number inside Storage with Counter ,than print it with my Printer class ?
here's what i've wrote so far:
public class Storage {
private int num;
public Storage(){
}
public synchronized void setNum(int num){
this.num = num;
}
public synchronized int getNum(){
return num;
}
public class Counter implements Runnable {
Storage s;
public Counter(Storage t){
s = t;
}
#Override
public void run() {
int i = 0;
while(true){
s.setNum(i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Printer implements Runnable {
Storage s;
public Printer(Storage s){
this.s= s;
}
#Override
public void run() {
while(true){
System.out.println(s.getNum());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class mainProg {
public static void main(String[] args){
Storage s = new Storage();
Counter c = new Counter(s);
Printer p = new Printer(s);
Thread c1 = new Thread(c);
Thread p2 = new Thread(p);
c1.start();
p2.start();
}
}
EDIT: i found out a solution, here it is:
public class Storage {
private int num;
private boolean available = false;
public Storage(){
}
public synchronized void setNum(int num){
while(available){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
available = true;
notifyAll();
this.num = num;
}
public synchronized int getNum(){
while(!available){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
available = false;
notifyAll();
return num;
}
}
This approach won't work, because it's not guaranteed that for every cycle of Counter a cycle of Printer will be executed in a parallel thread. You need to be able to store more than a one value in your Storage.
You can use BlockingQueue here and rewrite your Storage class like this:
public class Storage {
private BlockingQueue<Integer> numbers = new LinkedBlockingQueue<Integer>();
public void setNum(int num) {
try {
this.numbers.put(num);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public int getNum() {
try {
return numbers.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Note that if BlockingQueue is empty and Printer wants to get a new value, it will wait while a new element occurrs in the queue.