Consuming messages from MQ and merging in Spring JMS - multithreading

I use spring + MQ + Websphere Application server.
I want to consume messages from MQ asynchronously and combine the messages to have the List of messages to be easy to persist N number of Entities to Database in every single commit. (without stressing my target Oracle database with too many commits)
I use The DefaultMessageListenerContainer and I made the onMessage method synchronized to add on the messages(Till batch size) and I create the Thread to wait for the condition to meet(time/size) and push the messages to another thread which does Business Logic and DB persist.
Condition for the thread start:
Once the first message arrived inside onMessage method Thread has to wait to see 25 messages are received within 1000 milliseconds and If 25 messages are not reached within 1000 milliseconds it pushes the available number messages to another thread.
Issue:
I see the Thread is started only during the server stat up and not when onMessage method is invoked first time.
Any suggestions/ other way please to achieve collecting messages from Queue?
applicationContext.xml
<bean id="myMessageListener" class="org.mypackage.MyMessageListener">
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationName" ref="queue"/>
<property name="messageListener" ref="myMessageListener"/>
<property name ="concurrentConsumers" value ="10"/>
<property name ="maxConcurrentConsumers" value ="50"/>
</bean>
Listener :
package org.mypackage.MyMessageListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.mypackage.service.MyService;
public class MyMessageListener implements MessageListener {
private volatile long startTime = 0;
private volatile int messageCount;
private volatile List<String> messagesFromQueue = null;
private int batchSize = 25;
private long maximumBatchWaitTime = 1000;
#Autowired
private MyService myService;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
boolean threadRun = true;
while (threadRun) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("InterruptedException is caught inside run method");
}
if ((messageCount >0 && messageCount == batchSize)) {
System.out.println("----Batch size Reached----");
threadRun = false;
processMsgsFromQueue(messagesFromQueue);
} else {
if (maximumBatchWaitTime > (System.currentTimeMillis() - startTime)) {
System.out.println("----Time limit is not reached----");
threadRun = true;
} else {
threadRun = false;
System.out.println("----Time limit is reached----");
processMsgsFromQueue(messagesFromQueue);
}
}
}
}
});
{
thread.start();
}
#Override
public synchronized void onMessage(Message message) {
if (messageCount == 0) {
startTime = System.currentTimeMillis();
messagesFromQueue = new ArrayList<String>();
System.out.println("----First Message Arrived at----"+startTime);
}
try {
messageCount++;
TextMessage tm = (TextMessage) message;
String msg = tm.getText();
messagesFromQueue.add(msg);
if (messageCount == 0) {
thread.start();
}
} catch (JMSException e1) {
e1.printStackTrace();
}
}
private void processMsgsFromQueue(List<String> messageFromQueue) {
System.out.println("Inside processMsgsFromQueue");
messageCount = 0;
messagesFromQueue = null;
if(!messageFromQueue.isEmpty()) {
this.myService.insertMsgsFromQueueToDB(messageFromQueue);
}
}
}

you need to synchronize access to messagesFromQueue too.
List messagesFromQueue = Collections.synchronizedList(new ArrayList());
...
synchronized (messagesFromQueue) {
Iterator i = messagesFromQueue.iterator(); // Must be in synchronized block
while (i.hasNext())
...
}
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList(java.util.List)
on each call to processMsgsFromQueue you'll have a NullPointerException!!
private void processMsgsFromQueue(List<String> messageFromQueue) {
System.out.println("Inside processMsgsFromQueue");
messageCount = 0;
messagesFromQueue = null;
if(!messageFromQueue.isEmpty()/*messageFromQueue is null!!*/) {
this.myService.insertMsgsFromQueueToDB(messageFromQueue);
}
}
it is better to persist messages and when commit is ok you clear the list and reset the counter.
package org.mypackage.MyMessageListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.mypackage.service.MyService;
public class MyMessageListener implements MessageListener {
private volatile long startTime = 0;
private volatile int messageCount;
private volatile List<String> messagesFromQueue = null;
private int batchSize = 25;
private long maximumBatchWaitTime = 1000;
#Autowired
private MyService myService;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
boolean threadRun = true;
while (threadRun) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("InterruptedException is caught inside run method");
}
if ((messageCount >0 && messageCount == batchSize)) {
System.out.println("----Batch size Reached----");
threadRun = false;
processMsgsFromQueue(messagesFromQueue);
} else {
if (maximumBatchWaitTime > (System.currentTimeMillis() - startTime)) {
System.out.println("----Time limit is not reached----");
threadRun = true;
} else {
threadRun = false;
System.out.println("----Time limit is reached----");
processMsgsFromQueue(messagesFromQueue);
}
}
}
}
});
#Override
public synchronized void onMessage(Message message) {
if (messageCount == 0) {
startTime = System.currentTimeMillis();
messagesFromQueue = new ArrayList<String>();
System.out.println("----First Message Arrived at----"+startTime);
}
try {
messageCount++;
TextMessage tm = (TextMessage) message;
String msg = tm.getText();
messagesFromQueue.add(msg);
if (thread.getState() == Thread.State.NEW) {
thread.start();
}
} catch (JMSException e1) {
e1.printStackTrace();
}
}
private void processMsgsFromQueue(List<String> messageFromQueue) {
System.out.println("Inside processMsgsFromQueue");
if(!messageFromQueue.isEmpty()) {
this.myService.insertMsgsFromQueueToDB(messageFromQueue);
}
messageCount = 0;
messagesFromQueue = null;
}
}

Related

Why this code is giving IllegalMonitor Exception, when doing synchronization on instance variable

If I do synchronization on the lock, an Object, it works properly. However, if I do synchronization on number, an Integer, it throws an exception. Please help.
Below is my code:
package synchronization;
public class EvenOddThread implements Runnable {
int reminder;
Integer number = 1;
static Object lock = new Object();
public EvenOddThread( int reminder)
{
this.reminder = reminder;
}
public void run()
{
while(number < 10)
{
synchronized (number)
{
while(number %2 != reminder)
{
try
{
System.out.println(Thread.currentThread().getName()+" is waiting at "+number+" "+reminder);
number.wait();
}
catch(Exception e)
{
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+ " "+number );
number = number +1;
System.out.println(number);
//synchronized (lock) {
number.notifyAll();
//}
}
}
}
}

JavaFX Concurrency and Tasks (running threads in Task)

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 :))

SocketTimeoutException when testing on Android Studio simulator

When I attempt to connect through a socket to my Android App, I get the following error:
10-02 01: 32: 30.295 1738-1892 / me.schat E / schat / SimpleSocket: java.net.SocketTimeoutException: failed to connect to schat.me/188.40.116.82 (port 7667) after 20000ms
This error occurs only in the emulator. When i test directly on the phone it works.
Internet works on the emulator, the browser opens any website.
My socket code in its entirety
package me.schat.net;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import javax.net.SocketFactory;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class SimpleSocket {
private static final String TAG = "schat/SimpleSocket";
private final Object m_sendLock = new Object();
private boolean m_authorized = false; // true после успешной авторизации.
private DataInputStream m_in; // Поток чтения транспортных пакетов.
private DataOutputStream m_out; // Поток записи транспортных пакетов.
private Handler m_handler; // Объект доступа к потоку отправки пакетов.
private int m_reconnects = 0; // Число попыток восстановить соединение.
private long m_rxSequence = 0; // Счётчик полученных пакетов.
private long m_txSequence = 0; // Счётчик отправленных пакетов.
private Network network; // Информация для подключения.
private PacketListener m_packets; // Слушатель пакетов.
private Socket m_socket; // Сокет подключения.
private SocketListener m_listener; // Слушатель сокета.
private Thread m_thread; // Поток чтения пакетов.
private Timer m_timer; // Таймер обслуживающий соединение.
private TimerTask m_killTask; // Задача для отключения от сервера, если он не ответил за определённое время.
private TransportReader m_reader; // Объект чтения транспортных пакетов.
private ByteArrayOutputStream m_send = new ByteArrayOutputStream(); // Поток отправки пакетов.
public SimpleSocket(SocketListener listener, PacketListener packets) {
m_listener = listener;
m_packets = packets;
m_reader = new TransportReader(this);
m_timer = new Timer("SocketTimer");
HandlerThread thread = new HandlerThread("simplesocket-thread");
thread.start();
m_handler = new Handler(thread.getLooper());
}
public boolean connect(Network network) {
this.network = network;
return connect();
}
public boolean connect() {
Log.d(TAG, "connect()");
if ((m_thread != null && m_thread.isAlive()) || network == null)
return false;
m_thread = new Thread(new Runnable() {
public void run() {
Log.d(TAG, "RUN " + Thread.currentThread().getId());
int port = network.uri.getPort();
if (port == -1)
port = Protocol.DEFAULT_PORT;
try {
SocketAddress sockaddr = new InetSocketAddress(network.uri.getHost(), port);
SocketFactory factory = SocketFactory.getDefault();
m_socket = factory.createSocket();
m_socket.setTcpNoDelay(true);
m_socket.setKeepAlive(true);
m_socket.connect(sockaddr, Protocol.CONNECT_TIMEOUT);
m_in = new DataInputStream(new BufferedInputStream(m_socket.getInputStream()));
m_out = new DataOutputStream(new BufferedOutputStream(m_socket.getOutputStream()));
} catch (IOException ioe) {
Log.e(TAG, ioe.toString());
reconnect();
return;
}
catch (NullPointerException npe) {
Log.e(TAG, npe.toString());
reconnect();
return;
}
ping();
m_reconnects = 0;
m_listener.onConnect();
m_listener.onAuthRequired();
try {
m_reader.start(m_in);
} catch (IOException ioe) {
Log.e(TAG, "Socket read exception", ioe);
reconnect();
}
}
});
m_thread.start();
return true;
}
public boolean send(final WritablePacket packet) {
List<WritablePacket> packets = new ArrayList<WritablePacket>();
packets.add(packet);
return send(packets);
}
public boolean send(final List<WritablePacket> packets) {
if (packets.isEmpty())
return false;
m_handler.post(new Runnable() {
public void run() {
synchronized (m_sendLock) {
try {
List<byte[]> raws = new ArrayList<byte[]>(packets.size());
int options = Protocol.NO_OPTIONS;
for (WritablePacket packet : packets) {
final byte[] raw = packet.write(m_send).toByteArray();
raws.add(raw);
if (raw.length > 65535)
options = Protocol.HUGE_PACKETS;
}
new TransportWriter(m_out, raws, m_txSequence, options);
m_txSequence++;
} catch (IOException ioe) {
Log.e(TAG, "Send failed", ioe);
}
}
}
});
return true;
}
public final Network getNetwork() {
return network;
}
public final PacketListener packets() {
return m_packets;
}
public final synchronized boolean isAuthorized() {
return m_authorized;
}
public final synchronized void setAuthorized(boolean authorized) {
m_authorized = authorized;
}
public final void leave() {
m_reconnects = -1;
disconnect();
}
/**
* Отключение от сервера.
*/
public final void disconnect() {
if (m_socket == null)
return;
m_handler.post(new Runnable() {
public void run() {
try {
if (m_socket != null) {
m_socket.close();
m_socket = null;
}
} catch (IOException ioe) {
Log.e(TAG, "Error while disconnecting", ioe);
}
if (m_thread != null) {
m_thread.interrupt();
m_thread = null;
}
}
});
}
public final void ping() {
if (m_killTask != null)
m_killTask.cancel();
m_timer.schedule(new TimerTask() {
public void run() {
if (isAuthorized()) {
transmit(new byte[0], Protocol.INTERNAL_PACKET);
m_killTask = new TimerTask() {
public void run() {
disconnect();
}
};
m_timer.schedule(m_killTask, Protocol.REPLY_TIMEOUT);
} else
disconnect();
}
}, Protocol.IDLE_TIMEOUT);
}
private void reconnect() {
if (m_thread != null) {
m_thread.interrupt();
m_thread = null;
}
if (m_reconnects == -1)
return;
if (m_reconnects >= Protocol.MAX_FAST_RECONNECTS + Protocol.MAX_NORMAL_RECONNECTS)
m_reconnects = 0;
++m_reconnects;
m_timer.schedule(new TimerTask() {
public void run() {
connect();
}
}, m_reconnects <= Protocol.MAX_FAST_RECONNECTS ? Protocol.FAST_RECONNECT_TIME : Protocol.NORMAL_RECONNECT_TIME);
m_listener.onReconnect();
}
private boolean transmit(final byte[] packet, final int options) {
List<byte[]> packets = new ArrayList<byte[]>();
packets.add(packet);
return transmit(packets, options);
}
private boolean transmit(final List<byte[]> packets, final int options) {
// Log.d(TAG, "transmit(List<byte[]> packets)");
if (packets.isEmpty())
return false;
m_handler.post(new Runnable() {
public void run() {
synchronized (m_sendLock) {
try {
new TransportWriter(m_out, packets, m_txSequence, options);
if (options != Protocol.INTERNAL_PACKET)
m_txSequence++;
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
return false;
}
}

Thread synchronization with multiple objects

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);
}
}

Implementing busy wait with a pair of flags

I am trying to implement a busy waiting mechanism, using 2 flags. I get a deadlock, but just can't understand why... it looks to me as if it should work...
sorry for the long code, That's the shortest I succeeded to make it.
package pckg1;
public class MainClass {
public static void main(String[] args) {
Buffer b = new Buffer();
Producer prod = new Producer(b);
Consumer cons = new Consumer(b);
cons.start();
prod.start();
}
}
class Producer extends Thread {
private Buffer buffer;
public Producer(Buffer buffer1) {
buffer = buffer1;
}
public void run() {
for (int i = 0; i < 60; i++) {
while (!buffer.canUpdate)
;
buffer.updateX();
buffer.canUpdate = false;
buffer.canUse = true;
}
}
}
class Consumer extends Thread {
private Buffer buffer;
public Consumer(Buffer buffer1) {
buffer = buffer1;
}
public void run() {
for (int i = 0; i < 60; i++) {
while (!buffer.canUse)
;
buffer.consumeX();
buffer.canUse = false;
buffer.canUpdate = true;
}
}
}
class Buffer {
private int x;
public boolean canUpdate;
public boolean canUse;
public Buffer() {
x = 0;
canUpdate = true;
}
public void updateX() {
x++;
System.out.println("updated to " + x);
}
public void consumeX() {
System.out.println("used " + x);
}
}
I recommend that all the logic concerning Buffer should go into that class.
Also, accessing (and modifying) the flags must be protected, if 2 or more have access to it. That's why I put synchronised to the 2 methods.
class Buffer {
private int x;
private boolean canUpdate;
private boolean canUse;
public Buffer() {
x = 0;
canUpdate = true;
}
public synchronised void updateX() {
x++;
System.out.println("updated to " + x);
canUpdate = false;
canUse = true;
}
public synchronised void consumeX() {
System.out.println("used " + x);
canUpdate = true;
canUse = false;
}
public synchronised boolean canUse() {
return canUse;
}
public synchronised boolean canUpdate() {
return canUpdate;
}
}
Also, remove the canUpdate and canUse writes from the Producer and Consumer classes, and replace the reads (in the conditons) with the methods.
Also, it would be useful to introduce some Thread.sleep(100) in the waiting loops.

Resources