user2121 user2121 - 5 months ago 12
Java Question

static varibale cant be changed from a thread

in the below code, I create the class FMSHandler to process a string value passed to it from the main method as follwos

while (true) {
fmsHandler.process("param1_" + (++cnt) + ", param2_" + (cnt));
}


what i want to do is, to allow the processing to be performed every 3 seconds. or in other words, every 3 seconds i read the message passed from the main throught the previously mentioned code and perform
further processing. to do so, i created a static boolean variable called sIsProcessing to regulate the processing. this static variable is initially false and as long as there is
a message being processed it will be true and it will be set back to false when the thread the performs processing finihes as shown in the code below.

the problem i am facing is, despite the while-loop runs for ever, the processing is applied once and it is NOT repeated every 3 seconds as i expected it.

please have alook at the code and let me know where is the mistake

main:

public class Main {

private final static String TAG = Main.class.getSimpleName();

public static void main(String[] args) {
FMSHandler fmsHandler = new FMSHandler();
long startTime = TimeUtils.getTSSec();
int cnt = 0;

while (true) {
fmsHandler.process("param1_" + (++cnt) + ", param2_" + (cnt));
}
}


}

FMSHandler :

public class FMSHandler {
private final static String TAG = FMSHandler.class.getSimpleName();
private static boolean sIsProcessing = false;
private static int sCnt = 0;

public void process(String fmsMsg) {

if (!sIsProcessing) {
sIsProcessing = true;
Log.w(TAG, "FMSHandler", "new task to be processed");
new HandlerThread(HandlerThread.class.getSimpleName() + "_" + (FMSHandler.sCnt++), fmsMsg).start();
}

}

class HandlerThread extends Thread {
private String[] mSplittedFMS = null;
private String mThreadName = "";

public HandlerThread(String threadName, String fmsMsg) {
// TODO Auto-generated constructor stub
this.setName(threadName);
this.mSplittedFMS = this.toArray(fmsMsg);
}

private String[] toArray(String fmsMsg) {
// TODO Auto-generated method stub
return fmsMsg.split(",");
}

public void run() {
Log.w(TAG, "HandlerThread.run()", this.getName() + " started");

for (int i = 0; i < this.mSplittedFMS.length; i++) {
Log.i(TAG, "HandlerThread.run()", "this.mSplittedFMS: " + this.mSplittedFMS[i]);
}

try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Log.w(TAG, "HandlerThread.run()", this.getName() + " finished");
sIsProcessing = false;
}
}


}

Answer

You should declare the sIsProcessing variable as volatile or use an AtomicBoolean.

Also, currently, a lot of the messages passed to process(...) will be skipped, I'm not sure if that is you're intention.

If you want to prevent messages from being skipped you will need to use synchronization to block the loop from the main thread while a message is being processed.

My suggestion will be to completely rewrite this and use a Timer and some kind of queue from the concurrency package like ArrayBlockingQueue.

Here is an example:

public static final ArrayBlockingQueue<String> messages = new ArrayBlockingQueue<>(100);
public static final AtomicBoolean keepRunning = new AtomicBoolean(true);
.....
new Thread(new Runnable(){
    public void run(){
        while(keepRunning.get()){
            String message = messages.take();// blocks until a message is avaiable
            synchronized(Thread.currentThread()){
                Thread.currentThread().wait(3000);// pause 3 seconds before starting to process the next message.
            }
        }
    }
}).start();

// add messages from some other class;
MessagesProcessor.messages.add("some message");