How to handle the thread pool where one is polling while the other should update new incoming data after processing.
The program execution beings in a controller class which has a main method and thread pool:
The main class Controller
public static void main(String[] args) throws InterruptedException {
RunnableController controller = new RunnableController();
Accumulator acque = new Accumulator();
controller.initializeDb();
controller.initialiseThreads(acque);
controller.initialUpdate(acque);
}
The Run method for Polling class:
public void run() {
int seqId = 0;
List<KpiMessage> list = null;
while(true) {
try{
list = fullPoll(seqId);
if (!list.isEmpty()) {
accumulator.manageIngoing(list);
}
} catch (Exception e){
e.printStackTrace();
}
}
}
public List<KpiMessage> fullPoll(int lastSeq) throws Exception {
Statement st = dbConnection.createStatement();
System.out.println("Polling");
ResultSet rs = st.executeQuery("Select * from msg_new_to_bde where ACTION = 804 and SEQ >" +
lastSeq + "order by SEQ DESC");
return pojoCol;
}
Run method for processing:
public void run() {
try {
generate(accumulator.outgoingQueue);
accumulator.manageOutgoing(accumulator.outgoingQueue, dbConnection);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Method for updating into Database
public void updateDb(Collection<KpiMessage> updatedQueue, Connection dbConnection) throws
SQLException{
for(KpiMessage pojoClass : updatedQueue){
Statement stmtupd = dbConnection.createStatement();
System.out.println("Updating");
String query = "UPDATE msg_new_to_bde SET KEYINFO1= 'Processed', KEYINFO2 = 'Updated'
WHERE ACTION = 804";
stmtupd.executeUpdate(query);**My Execution stops here**
Finally an accumulator class for maintaing all these queues:
public boolean isUsed = false;
public synchronized void manageIngoing(List<KpiMessage> list){
if(this.isUsed){
try {
wait();
System.out.println("first wait");
} catch (Exception e1) {
e1.printStackTrace();
}
}
System.out.println("recived pass after update");
this.getIncomingQueue().addAll(list);
//incoming queue copied to outgoing queue
this.setOutgoingQueue(this.getIncomingQueue());
System.out.println("waiting");
System.out.println("new incoming message");
this.isUsed = false;
notifyAll();
}
/**
* Method which handles synchronization using wait and notify for outgoing messages after
polling
* #param outgoingQueue
* #param dbConnection
*/
public synchronized void manageOutgoing(Collection<KpiMessage> outgoingQueue, Connection
dbConnection){
if(!this.isUsed)
{
try {
System.out.println("second wait");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.isUsed = true;
DBhandler dbhandler = new DBhandler();
try {
dbhandler.updateDb(getOutgoingQueue(), dbConnection);
} catch (SQLException e) {
e.printStackTrace();
}
notifyAll();
}
}
My task and Question is :
1.The controller should handle both the threads Poller & processor and accumulator handles the incoming and outgoing queues, finally fed into to updated queue for updating DB after processing
2.My class here just does polling once, is not able to update ,execution stops at
3.Is my wait(), notifyALL() handle correct here.
How to achieve repeated polling and updation here?
Chances are, in this complex setting with five different questions, there will be no complete answer for everything. While waiting for those, you should read up on what java.util.concurrent has to offer, especially the concurrent collections with support for blocking reads and writes. Use wait() and notify() only if the JDK classes are not enough for you.
Related
I am exploring java.util.concurrent.*
Calculating the square and waiting using Thread.sleep(5000) , the program works as expected, but never terminates.
The red square in eclipse is "ON", that we usually use to terminate the program.
Can you please help in understanding why the program doesn't terminate on completion??
public static void main(String[] args) throws InterruptedException, ExecutionException {
// TODO Auto-generated method stub
try {
SquareCalculator sqC = new SquareCalculator();
sqC.display(1);
Future<Integer> result = sqC.calculate(5);
while(!result.isDone())
{
System.out.println("Waiting for the calculation");
Thread.sleep(1000);
//result.cancel(true);
}
Integer square = result.get();
System.out.println(square);
}catch(Exception e)
{
e.printStackTrace();
System.out.println("Calclulation was interrupted");
}
}
public class SquareCalculator {
private ExecutorService ex = Executors.newSingleThreadExecutor();
public void display(int i) {
// TODO Auto-generated method stub
System.out.println(i);
}
public Future<Integer> calculate(Integer inp)
{
try {
System.out.println("Before sending request");
Future<Integer> res = ex.submit(()->{
Thread.sleep(5000);
return inp*inp;
});
System.out.println("Request sent to caluclate and waiting for the result");
return res;
}catch(Exception e)
{
System.out.println("calculation was interrupted");
return null;
}
//return ex.submit(()->squareing(inp));
}
}
OUTPUT
1
Before sending request
Request sent to caluclate and waiting for the result
Waiting for the calculation
Waiting for the calculation
Waiting for the calculation
Waiting for the calculation
Waiting for the calculation
25
You need to refactor your code and return the object instead of Future. You should also shutdown executor when you are done.
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SquareCalculator {
private ExecutorService ex = Executors.newSingleThreadExecutor();
public void display(int i) {
// TODO Auto-generated method stub
System.out.println(i);
}
public Integer calculate(Integer inp) {
Integer result;
try {
System.out.println("Before sending request");
Future<Integer> res = ex.submit(() -> {
Thread.sleep(5000);
return inp * inp;
});
System.out.println("Request sent to caluclate and waiting for the result");
result = res.get();
ex.shutdown();
return result;
} catch (Exception e) {
System.out.println("calculation was interrupted");
return null;
}
//return ex.submit(()->squareing(inp));
}
public static void main(String[] args) throws InterruptedException,
ExecutionException {
// TODO Auto-generated method stub
try {
SquareCalculator sqC = new SquareCalculator();
sqC.display(1);
Integer result = sqC.calculate(5);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Calclulation was interrupted");
}
}
}
I would rather create an executor outside the Calculator class and the pass it in the constructor.
This way the application has control over the ExecutorService and shut it down when necessary.
Also, if you create more then one instance of a calculator, all instance use the same executor service, so you can control how many instance can run in parallel.
Blocking in the calculate method works, but defeats the purpose of using another thread to make an async calculation.
public static void main(String[] args) {
// The executor is created by the application and then
// passed to the calculator
ExecutorService executor = Executors.newCachedThreadPool();
SquareCalculator calculator = new SquareCalculator(executor);
// calculate does not block
Future<Integer> calculate = calculator.calculate(12);
try {
while(true) {
try {
// wait a limited amount of time for the computation to complete
Integer result = calculate.get(1, TimeUnit.SECONDS);
System.out.println(result);
if(calculate.isDone()) {
// If the computation was either complete or cancelled just quit
break;
}
} catch (TimeoutException e) {
// We expect timeouts so we don't quit the loop for them
System.out.println("Waiting for result");
}
}
} catch (InterruptedException | ExecutionException e) {
// If there was an error or the computation was interrupted just quit.
e.printStackTrace();
}
// Shut down the executor so we do not leak pools.
executor.shutdown();
}
public class SquareCalculator {
private ExecutorService ex;
public SquareCalculator(ExecutorService ex) {
super();
this.ex = ex;
}
public void display(int i) {
System.out.println(i);
}
public Future<Integer> calculate(Integer inp) {
try {
System.out.println("Before sending request");
Future<Integer> res = ex.submit(() -> {
Thread.sleep(5000);
return inp * inp;
});
System.out.println("Request sent to caluclate and waiting for the result");
return res;
} catch (Exception e) {
System.out.println("calculation was interrupted");
return null;
}
}
}
If you want the VM to shut down, call System.exit(). Yes, the VM can automatically close without calling that method as well; it does this if ALL still 'live' threads have the 'daemon' flag up (the Thread class has a .setDaemon method for this purpose), but that's bad code style. If the point is to shut down, then shut down (with System.exit).
Specifically here, the threads created by Executors.newSingleThreadExecutor(); aren't marked as daemon threads. You can fix that by supplying a thread creator to the call.
But, really, don't. Use System.exit.
I have 3 rfid readers where I am reading rfid tags. I am running those but for some reason I am only receiving info from the last reader(thread) that is being processed. What am I missing? The readers are in an array containing the ipaddress, username, port, password. Can I listen on the same service for all of them? I'm new to threads........TagInventory is the name of the class where all of this is located.
Here is the code:
private void Start() throws AlienReaderException, IOException{
ThreadStop = false;
service= new MessageListenerService(3900);
service.setMessageListener(this);
service.startService();
System.out.println("length of readers: "+Reader.ipAddress.length);
for (lastThreadId = 0; lastThreadId < Reader.ipAddress.length; lastThreadId++)
{
m_inventory[lastThreadId] = new AlienReader(Reader.ipAddress[lastThreadId], Reader.port, Reader.username[lastThreadId], Reader.password[lastThreadId]);
log.info("taginventory reader: "+ Reader.ipAddress[lastThreadId]+"Thread: "+lastThreadId);
m_run_process[lastThreadId] = new Thread(new StartInventoryThread(Reader.ipAddress[lastThreadId], Reader.port, Reader.username[lastThreadId], Reader.password[lastThreadId], m_inventory[lastThreadId]));
m_run_process[lastThreadId].start();
}
--lastThreadId;
try
{
// Thread.sleep(1000);
Thread.sleep(2000);
}
catch (Exception ex)
{
ex.getMessage();
}
}
class StartInventoryThread implements Runnable{
private String ip;
private int port;
private String user;
private String pwd;
private AlienReader ar;
StartInventoryThread(String ip, int port, String user, String pwd, AlienReader ar){
this.ip=ip;
this.port=port;
this.user=user;
this.pwd=pwd;
this.ar=ar;
}
#Override
public void run() {
try {
while(!stopInventory){
startRead(ip,port,user,pwd);
}
} catch (AlienReaderException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void startRead(String ip, int port, String user, String password) throws AlienReaderException, InterruptedException, UnknownHostException{
String myIP=InetAddress.getLocalHost().getHostAddress();
//System.out.println("ip"+ ip);
AlienReader ar= new AlienReader(ip, port, user, password);
ar.open();
//log.info("Reader" + ar.getIPAddress());
ar.setNotifyAddress(myIP, 3900);
ar.setNotifyFormat(AlienClass1Reader.TEXT_FORMAT);
//ar.setNotifyTrigger("TrueFalse");
ar.setNotifyTrigger("Add");
ar.setNotifyMode(AlienClass1Reader.ON);
// log.info("MessageListenerService has started for reader: " + ip);
//complete process in here
ar.autoModeReset();
ar.setAutoStopTimer(5000); // Read for 5 seconds
ar.setAutoMode(AlienClass1Reader.ON);
tagTable.setTagTableListener(tagTableListener);
tagTable.setPersistTime(3600);
//tagTable.setPersistTime(1800000);
ar.close();
long runTime = 10000; // milliseconds
long startTime = System.currentTimeMillis();
do {
Thread.sleep(1000);
} while(service.isRunning()
&& (System.currentTimeMillis()-startTime) < runTime);
// Reconnect to the reader and turn off AutoMode and TagStreamMode.
// log.info("\nResetting Reader");
ar.open();
ar.autoModeReset();
ar.setNotifyMode(AlienClass1Reader.OFF);
ar.close();
}
public static void main(String args[]){
Thread thr=new Thread(new Runnable(){
#Override
public void run(){
try {
new TagInventory();
} catch (AlienReaderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thr.start();
}
Overview
I see a number of issues and potential hazards in your logic throughout the code. I will step through each and guide you to the corresponding concepts that align with these issues.
Main
In your main(String args[]), add a join() call so that the calling thread (likely the main thread) can wait until Thread thr finishes before exiting.
public static void main(String args[]){
Thread thr=new Thread(new Runnable(){
#Override
public void run(){
try {
new TagInventory();
} catch (AlienReaderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
thr.start();
thr.join();
}
Start
Assuming you are expecting the threads to finish by the time the Start() function finishes I will explain how to obtain that functionality. Do not utilize Thread.sleep() as it is considered poor programming. Instead utilize the join() function. The forces the calling thread to wait or block until that thread has finished. The logic added below will cycle through each of the m_run_process and block until it has finished. If you have another location where you want to ensure they all finish, you can put the for-loop there instead.
private void Start() throws AlienReaderException, IOException{
ThreadStop = false;
service= new MessageListenerService(3900);
service.setMessageListener(this);
service.startService();
System.out.println("length of readers: "+Reader.ipAddress.length);
for (lastThreadId = 0; lastThreadId < Reader.ipAddress.length; lastThreadId++)
{
m_inventory[lastThreadId] = new AlienReader(Reader.ipAddress[lastThreadId], Reader.port, Reader.username[lastThreadId], Reader.password[lastThreadId]);
log.info("taginventory reader: "+ Reader.ipAddress[lastThreadId]+"Thread: "+lastThreadId);
m_run_process[lastThreadId] = new Thread(new StartInventoryThread(Reader.ipAddress[lastThreadId], Reader.port, Reader.username[lastThreadId], Reader.password[lastThreadId], m_inventory[lastThreadId]));
m_run_process[lastThreadId].start();
}
--lastThreadId;
for(Thread inventoryThread : m_run_process)
inventoryThread.join()
}
StartRead
There seems to be a lot of problems here where you are accesses non-thread-safe objects and variables; service, stopInventory, and tagTable (without seeing the full file I am making assumptions and I do not see synchronization anywhere). Now, I recommend reading up on the Java Memory Model, Java Memory Barrier, Atomic Operations, Synchronization, Thread-Safety, and the JVM. In essence, your logic can cause overwriting of data and/or threads see different caches values. To rectify you must make shared, mutable instances thread-safe through synchronization and atomicity.
public void startRead(String ip, int port, String user, String password) throws AlienReaderException, InterruptedException, UnknownHostException{
String myIP=InetAddress.getLocalHost().getHostAddress();
//System.out.println("ip"+ ip);
AlienReader ar= new AlienReader(ip, port, user, password);
ar.open();
//log.info("Reader" + ar.getIPAddress());
ar.setNotifyAddress(myIP, 3900);
ar.setNotifyFormat(AlienClass1Reader.TEXT_FORMAT);
//ar.setNotifyTrigger("TrueFalse");
ar.setNotifyTrigger("Add");
ar.setNotifyMode(AlienClass1Reader.ON);
// log.info("MessageListenerService has started for reader: " + ip);
//complete process in here
ar.autoModeReset();
ar.setAutoStopTimer(5000); // Read for 5 seconds
ar.setAutoMode(AlienClass1Reader.ON);
tagTable.setTagTableListener(tagTableListener);
tagTable.setPersistTime(3600);
//tagTable.setPersistTime(1800000);
ar.close();
long runTime = 10000; // milliseconds
long startTime = System.currentTimeMillis();
do {
Thread.sleep(1000);
} while(service.isRunning()
&& (System.currentTimeMillis()-startTime) < runTime);
// Reconnect to the reader and turn off AutoMode and TagStreamMode.
// log.info("\nResetting Reader");
ar.open();
ar.autoModeReset();
ar.setNotifyMode(AlienClass1Reader.OFF);
ar.close();
}
I have a problem with a part of my code. My program have a thread that is getting input from the keyboard and have several threads that are waiting for that input.
The users selects first to what thread he is going to send that input. So lets says that we have 3 threads (0,1,2) plus the thread that gets the keyboard input. The user will select first what thread he wants to interact with and after that he will send the actual data to that thread.
I have a piece of code that is taking care of that process. I use ´LinkedBlockingQueue´ to achieve it.
The keyboard thread puts data in the Queue and the "workers" (the other 3 threads) get that data from that queue.
The problem is that all the threads are listening for that same Queue so I put an ID in that Queue to let the threads know if the data is directed to them or to other thread.
Here is the code:
Thread Thread_OUT = new Thread(new Runnable() {
#SuppressWarnings("unchecked")
#Override
public void run() {
while(true) {
try {
Object recibido= sharedQueue.take();
sharedQueue.put(recibido);
//System.out.println("Im the thread "+ clientID+" and I got "+recibido.toString());
if(Integer.parseInt(recibido.toString())==clientID){ // If it is for me I get the data
String x = CommandShellServer.data.get(clientID); // just get the data (it is in a hashmap)
CommandShellServer.data.clear(); // empty the hashmap
sharedQueue.clear();
OUT = do_something(x);
}
else{ // If it is not I will forward it to other thread
Thread.currentThread().wait(100);
// sharedQueue.put(recibido);
// sharedQueue.clear();
}
As you can see in the code what I do is checking if the thread that is handling the information is the one that is directed to If it is, I process it, and if it is no I put that the data again in the queue to let the other threads to check for it.
If I select the thread 0 to interact with it works. If I select others it doesn't.
Get rid of the shared queue, and let each thread have its own. Then, when you get an input, just dispatch it to the queue of appropriate thread that is intended to receive it.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package Application;
import java.util.ArrayList;
import java.util.Scanner;
/**
*
* #author husseyn
*/
public class producteurConsomateur {
static Scanner clavier;
static ArrayList<String> queu;
public static void main(String[] args) {
queu=new ArrayList<>();
new Thread(){
#Override
public void run() {
clavier=new Scanner(System.in);
while (true) {
try {
sleep(1000);
} catch (Exception e) {
}
System.out.print("tape message :");
String nextLine = clavier.nextLine();
queu.add(nextLine);
// notifyAll();
}
}
}.start();
new Thread(){
#Override
public void run() {
while (true) {
try {
try {
wait();
} catch (Exception e) {
}
synchronized(this){
String get = queu.get(0);
String[] messageFormat = get.split(":");
String id=messageFormat[0];
if (id.toLowerCase().equals("id1")) {
String message=messageFormat[0];
queu.remove(0);
System.out.println("message recived to thread ID1 :"+message);
}}
} catch (Exception e) {
}
}
}
}.start();
new Thread(){
#Override
public void run() {
while (true) {
try {
try {
wait();
} catch (Exception e) {
}
synchronized(this){
String get = queu.get(0);
String[] messageFormat = get.split(":");
String id=messageFormat[0];
if (id.toLowerCase().equals("id3")) {
String message=messageFormat[0];
queu.remove(0);
System.out.println("message recived to thread ID3 :"+message);
}}
} catch (Exception e) {
}
}
}
}.start();
new Thread(){
#Override
public void run() {
while (true) {
try {
try {
wait();
} catch (Exception e) {
}
synchronized(this){
String get = queu.get(0);
String[] messageFormat = get.split(":");
String id=messageFormat[0];
if (id.toLowerCase().equals("id2")) {
String message=messageFormat[0];
queu.remove(0);
System.out.println("message recived to thread ID2 :"+message);
}}
} catch (Exception e) {
}
}
}
}.start();
}
}
And here I use a shared queue but you have to respect the message format is like id1:hello or id2:lol
Let's say we've got an SQL database (hsqldb) and want to run a number of queries on it which do not modify the content.
This takes a long time for some queries and I would like to run the queries in multiple threads.
So my question is: what is the best way to implement this?
I did not find any good samples to do this so I came up with the following (which I would love to get some comments on).
First, very briefly in words:
I use thread-safe collections to access the queries and to put the results in. The queries are executed in a number of worker threads. The results are processed in the main thread which checks for new results until all threads are finished.
Now the code:
Create thread-safe collections of queries and results:
ConcurrentLinkedQueue<String> queries = new ConcurrentLinkedQueue<String>()
ConcurrentLinkedQueue<ResultSet> sqlResults = new ConcurrentLinkedQueue<ResultSet>();
Create a number of threads and start them (edited):
ExecutorService executorService = Executors.newFixedThreadPool(4);
for(int i=0; i<4; i++){
executorService.execute(new QueryThread(sqlResults, queries));
}
Within the thread class QueryThread a connection is opened and queries are executed as long as there are any left:
private class QueryThread implements Runnable {
private ConcurrentLinkedQueue<ResultSet> sqlResults;
private ConcurrentLinkedQueue<String> queries;
public QueryThread(ConcurrentLinkedQueue<ResultSet> sqlResults, ConcurrentLinkedQueue<String> queries){
this.sqlResults = sqlResults;
this.queries = queries;
}
#Override
public void run(){
Connection connThr = null;
try{
try {
connThr = DriverManager.getConnection(dbModeSave, "sa", "");
connThr.setAutoCommit(false);
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String currentQuery;
do {
currentQuery = queries.poll(); // get and remove element from remaining queries
if (currentQuery != null) { // only continue if element was found
try {
Statement stmnt = connThr.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
try {
ResultSet resultSet = stmnt.executeQuery(currentQuery);
sqlResults.add(resultSet);
} catch (SQLException e) {
// (Do something specific)
} finally {
stmnt.close();
}
} catch (SQLException e) {
// (Do something specific)
}
}
} while (currentQuery != null);
} finally {
if (connThr != null) {
try {
connThr.close();
} catch (SQLException e) {
// Nothing we can do?
}
}
}
}
}
From the original thread I check, if the threads are all finished and therefore all queries were processed (edited).
while (!executorService.isTerminated()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
while (!sqlResults.isEmpty()) {
ResultSet result = sqlResults.poll();
//process result and close it in the end
}
}
Java standard sulution for parallel processing is ThreadPoolExecutor. Try it.
I am writing code that communicates on serially with several machines. Each machine interacts with an instance of a communicator class and that class has a serial port event listener.
When the machine recieves enough data it peforms a test that is quadratic. (cant be helped as the test itself is quadratic) and the input can be large. As a result I am afraid that some of the serial events wont be registered if the code is doing the calculation.
As a solution I considered creating a Thread that runs the calculation and setting it to sleep during its loop for a time determined by the number of machines connected. However I then thought that maybe it would be a better idea if I could put that Thread asleep from the serialevent method? is this possible or will the thread not run until the method that is running finishes?
Now in the code below I have included the Thread.sleep within the Calculations method as this is what I was going to do if the serialevent cant interupt the thread
private class CalculationThread implements Runnable{
#Override
public void run()
{
calculateResult();
}
}}
private void calculateResult() {
ArrayList<Double> theoretical_vals;
ArrayList<ArrayList<Double>> theoretical_curves = new ArrayList();
double current_maxdiff, maxdiff;
double ao = measurements.get(0).getMeasurement();
theoretical_vals = RadioCalculations.theoreticalVals(measurements, hf, ao);
theoretical_curves.add(theoretical_vals);
int index = 1;
for (MeasurePoint m : measurements) {
theoretical_vals = RadioCalculations.calibratecontrolValues(measurements, index, hf);
try {
Thread.sleep(20*(parent.getNumberOfTests()-1));}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
theoretical_curves.add(theoretical_vals);
index++;
}
index = 1;
maxdiff = 0;
for (ArrayList a : theoretical_curves) {
try {
Thread.sleep(20*(parent.getNumberOfTests()-1));
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
current_maxdiff = compareValues(a, measurements);
if (current_maxdiff > maxdiff) {
if (current_maxdiff > pass_limit) {
passed = false;
failed_measurementpoint = index;
break;
}
maxdiff = current_maxdiff;
index++;
}
}
passed = true;
max_dev = maxdiff;
logResults();
}
public void serialEvent(SerialPortEvent spe) {
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
pauseListen(false);
if (spe.getEventType()== SerialPortEvent.DATA_AVAILABLE){
try {
while (inputStream.available() > 0) {
numBytes = inputStream.read(readBuffer);}}
catch (IOException e) {e.printStackTrace();}
input_line= new String(readBuffer,0,numBytes);
input_line = input_line.replaceAll("[\n\r]","*");
buffer.append(input_line);
if (input_line.contains("*")){
input_line= buffer.toString();
input_line = input_line.replaceAll("[*]","");
buffer.setLength(0);
pauseListen(true);
update(input_line);}}
}
}
You could use a BlockingQueue (since Java 5) for put the new calculations in this queue while there is one calculation in process.
First, you need a wrapper class for you received data of the serial port:
class CalculationWrapper {
// fields
// getters setters
public void calculateResult() {
// operations
}
}
The method calculateResult for do the calculations can be in this class or in the next class:
class Calculator implements Runnable {
private final BlockingQueue<CalculationWrapper> queue;
Calculator(BlockingQueue<CalculationWrapper> q) {
queue = q;
}
public void run() {
try {
while (true) {
CalculationWrapper wrapper = queue.take();
wrapper.calculateResult();
}
} catch (InterruptedException ex) {
// log error
}
}
}
The method take wait until there is more new calculations in the queue.
The class for the listener of events of serial port (and for put the new calculations) could be:
class Receiver implements Runnable, SerialPortEventListener {
private final BlockingQueue<CalculationWrapper> queue;
Receiver(BlockingQueue q) {
queue = q;
}
public void run() {
try {
while (true) {
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
// log
}
}
public void serialEvent(SerialPortEvent evt) {
switch (evt.getEventType()) {
case SerialPortEvent.DATA_AVAILABLE:
try {
// read
CalculationWrapper wrapper = new CalculationWrapper();
// set data on wrapper
queue.put(wrapper);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
And the setup class o main class:
class Setup {
public static void main(String args[]) {
// get port
// register listener
BlockingQueue q = new ArrayBlockingQueue(10);
Receiver p = new Receiver(q);
Calculator c1 = new Calculator(q);
new Thread(p).start();
new Thread(c1).start();
}
}
This in one way. See more:
Lesson: Concurrency (The Java Tutorials > Essential Classes)
SerialPort example « javax.comm « Java by API
The Java Communications API: A Working Example - By Rick Proctor