Using synchronized block to protect against infinite loops - java

I'm currently developing an app that in some test cases, goes on a infinite loop, but if I redo the same tests, it goes on well. To prevent it, I'm using a secondary thread to monitor the time passed since the start of a task, but I'm currently not using synchronized blocks, because I don't know how to.
Here is an example:
public class ThreadHarvest {
private static final ReentrantLock lock = new ReentrantLock();
private static boolean safe;
public static void main(String[] args) throws InterruptedException
{
Thread task = new Thread(() ->{
lock.lock();
safe = false;
for (long i = 10000000L; i > 0L; --i)
System.out.println(i);
safe = true;
lock.unlock();
System.out.println("Safe ended!");
});
task.start();
while (lock.isLocked() == false);
lock.tryLock(5, TimeUnit.SECONDS);
if (!safe)
{
task.stop();
System.out.println("Force ended!");
}
}
}
Also, there is a specific area that is guaranteed to be safe, which is just after the lock is released. And I know too that the stop method is deprecated, so if you happen to have some good ideas to make it less error prone, I'd be very thankful :D

I don't really understand your question but here are some general comments about your code.
You should never have a spin loop like that. I'd add a Thread.sleep(10); or something.
With locks, you should always put your unlock in a lock; try { } finally { unlock; }. Then you know your lock will be unlocked even if it throws an exception.
If you are accessing a field in two different threads you must protect it somehow. You could use an AtomicBoolean for safe or mark it as a volatile boolean otherwise the main thread might not see any changes to it. There are no guarantees of memory synchronization with isLocked() or tryLock().
Instead of your lock and safe, how about just trying to do a task.join(5, TimeUnit.SECONDS) and then test if (task.isAlive()) { killItWithFire(); }.
I'm currently developing an app that in some test cases, goes on a infinite loop,
Seems to me like you should be be concentrating your time fixing this problem. The thread.stop() is a real hack.

Related

How to properly use synchronized block or locks to ensure variable visibility?

Sample code:
public class TestTestTest {
private void setFalseFlag() {
this.keepRunning = false;
System.out.println("keepRunning is false");
}
private boolean keepRunning = true;
public static void main(String[] args) throws InterruptedException {
TestTestTest t = new TestTestTest();
Thread startLoop = new Thread(() -> {
System.out.println("before loop");
while (t.keepRunning) {}
});
Thread flagChanger = new Thread(() -> {
System.out.println("before setting flag");
t.setFalseFlag();
});
startLoop.start();
Thread.sleep(1000);
flagChanger.start();
}
}
This code sample starts and never finishes, because keepRunning changes are not visible to the other thread. Of course, if I use volatile or AtomicBolean for keepRunning programm starts and stops properly.
But, as far as I know synchronized block or locks provides flushes to main memory on entering and on exiting or smth like that, info taken from documentation. But I can't understand how to implement it on this code sample. Looks like it is not even possible to sync on one monitor here.
Oracle Documentation
All Lock implementations must enforce the same memory synchronization semantics as provided by the built-in monitor lock:
A successful lock operation acts like a successful monitorEnter action
A successful unlock operation acts like a successful monitorExit action
JSR-133 FAQ
But there is more to synchronization than mutual exclusion. Synchronization ensures that memory writes by a thread before or during a synchronized block are made visible in a predictable manner to other threads which synchronize on the same monitor. After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory. We will then be able to see all of the writes made visible by the previous release.
So here is the question, am I right that it is not possible here? Or if not, how to do it properly?
"synchronized block or locks provides flushes to main memory on entering and on exiting"
You can't because you're accessing keepRunning directly. That's why volatile works, because you can put it directly on the field. If you want to use synchronized, you need a section of code that only accesses keepRunning while a lock is held (in computer science this section of code is called a "critical section").
// CHANGE
private synchronized void setFalseFlag() {
// CHANGE
run = false;
System.out.println("keepRunning is false");
}
// CHANGE
private synchronized boolean keeRunning() {
// CHANGE
return run;
}
// CHANGE
private boolean run = true;
public static void main(String[] args) throws InterruptedException {
TestTestTest t = new TestTestTest();
Thread startLoop = new Thread(() -> {
System.out.println("before loop");
// CHANGE
while (t.keepRunning()) {}
});
You can do:
private Boolean keepRunning = true; //change to object so it can be synchronized one
...
while (true)
{
synchronized (t.keepRunning)
{
if (!t.keepRunning)
{
break;
}
}
}
But better do volatile thingy.
I think the reason your version doesn't break is that java isn't guaranteed to watch variables changed from other threads unless it's volatile, therefor the while loop check is optimized to true.

can synchronized guarantee variables outside synchronous code block visible between threads?

I have a question about visibility between varaibles in threads (see below), while loop cant stop after I comment synchronized (this){}, but uncomment it, while loop can stop normally, which prove synchronized(this){} can make shared varabiles visible between threads.
I know JMM's happens before principle is used to guarantee shared variables visible each other, but I dont know the above code satisfy which principle of happens before? or can synchronized guarantee variables outside synchronous code block visible between threads?
#Slf4j(topic = "threadVisible")
public class ThreadVisible {
int i = 0;
public void go() {
new Thread(()-> {
while (true) {
synchronized (this){}
if (i != 0) break;
}
}).start();
}
public static void main(String[] args) throws InterruptedException {
ThreadVisible t = new ThreadVisible();
t.go();
Thread.sleep(3000);
t.i = 10; //
log.info("end");
}
}
There is no happens before in your code between t.i = 10 and if (i != 0), even with the synchronized statement. The reason is that to create a hb relationship, you need to synchronize the assignment t.i = 10 too.
The machine (JVM + OS + CPU) on which you run this probably does more than required when calling synchronized and effectively synchronizes everything. On a different machine you could experience an infinite loop.
Actually you could replace synchronized (this){} by System.out.println("OK") and you would probably get the same behaviour, just because println is synchronized.
Also empty synchronized statements are rarely what you need, although it makes no difference in your case because of the while loop.

Java code exits after some seconds due to concurrency

I am writing the same code on tutorial. But in tutorial the program never exits, my in my computer it exits after 4 seconds. Why?
tutorial with exact time where this code is shown: https://youtu.be/vzBw1LPupnA?t=169
public class Main {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested) {
i++;
System.out.println("i = " + i);
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
The reason that you are seeing different behavior on your machine and in the video is because the program has unspecified behavior. (Or to put it another way, it is not thread-safe.)
You have two threads accessing and updating a shared variable without taking the necessary steps that will guarantee that changes made by one thread are visible to the other. What happens in that case is not specified.
In some cases (e.g. on some platforms) the changes will be visible, either immediately or within a short time.
On others, the changes may never be visible.
In technical terms, there must be a happens-before relationship between the write by on thread and the subsequent read by the other thread. This can be provided by both threads synchronizing on the same mutex or lock, by using a volatile variable, and in other ways. But this code doesn't do any of those things, so there is no guarantee that the state change will be visible.
For more details, read about the Java Memory Model.
The above is sufficient to explain the difference, but there may be a more direct explanation.
In practice, something like a System.out.println can lead to changes in the visibility. Underneath the covers, the println call will typically result in synchronization on the output stream's buffers. That can result in a serendipitous happens-before that is sufficient to guarantee visibility. But this behavior is not specified, so you should not rely on it.
At any rate, adding trace statements can change the behavior of multi-threaded coded. And the fact that you (apparently) added them in your version is a second possible explanation for the difference.
The bottom line here is that a program with a memory visibility flaw is broken, but you may not be able to demonstrate that it is broken.
As the excellent Answer by Stephen C says, your code is not thread-safe.
Establishing an AtomicBoolean early on addresses the visibility problem explained in that other Answer. This class is a thread-safe wrapper around its payload boolean value.
The volatile keyword is another solution. But I find the Atomic… classes simpler and more obvious.
Also, in modern Java we rarely need to address the Thread class directly. Instead, use the Executors framework. Define your task as a Runnable or Callable, and submit to an executor service.
Something like this untested code.
public class Main {
private static final AtomicBoolean stopRequested = new AtomicBoolean( false ) ;
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
int i = 0;
while ( ! stopRequested.get() ) {
i++;
System.out.println("i = " + i);
TimeUnit.MILLISECONDS.sleep(100); // Don’t spin too fast.
}
};
ExecutorService es = Executors.newSingleThreadedExecutorService() ;
es.submit( task ) ;
TimeUnit.SECONDS.sleep(1);
stopRequested.set( true ) ;
TimeUnit.SECONDS.sleep(1);
// Shut down here executor service. Boilerplate taken from Javadoc.
es.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!es.awaitTermination(60, TimeUnit.SECONDS)) {
es.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!es.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Executor service did not terminate");
}
} catch (InterruptedException ex) {
// (Re-)Cancel if current thread also interrupted
es.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}

My java unit test failed if there is a call to wait method inside a synchronized method

I am learning multi-threads programming in java recently. And I don't understand why the following test case will fail. Any explanation will be much appreciated.
Here is MyCounter.java.
public class MyCounter {
private int count;
public synchronized void incrementSynchronized() throws InterruptedException {
int temp = count;
wait(100); // <-----
count = temp + 1;
}
public int getCount() {
return count;
}
}
This is my unit test class.
public class MyCounterTest {
#Test
public void testSummationWithConcurrency() throws InterruptedException {
int numberOfThreads = 100;
ExecutorService service = Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(numberOfThreads);
MyCounter counter = new MyCounter();
for (int i = 0; i < numberOfThreads; i++) {
service.submit(() -> {
try {
counter.incrementSynchronized();
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
});
}
latch.await();
assertEquals(numberOfThreads, counter.getCount());
}
}
But if I remove wait(100) from the synchronized method incrementSynchronized, the test will succeed. I don't understand why wait(100) will affect the result.
Solomons suggestion to use sleep is a good one. If you use sleep instead of wait, you should see the test pass.
Using wait causes the thread to relinquish the lock, allowing other threads to proceed and overwrite the value in count. When the thread's wait times out, it acquires the lock again, then writes a value to count that may be stale by now.
The typical usage of wait is when your thread can't do anything useful until some condition is met. Some other thread eventually satisfies that condition and a notification gets sent that will inform the thread it can resume work. In the meantime, since there is nothing useful the thread can do, it releases the lock it is holding (because other threads need the lock in order to make progress meeting the condition that the thread is waiting for) and goes dormant.
Sleep doesn't release the lock so there won't be interference from other threads. For either the sleeping case or the case where you delete the wait call, the lock is held for the duration of the operation, nothing else can change count, so it is threadsafe.
Be aware that in real life, outside of learning exercises, sleeping with a lock held is usually not a great idea. You want to minimize the time that a task holds a lock so you can get more throughput. Threads denying each other the use of a lock is not helpful.
Also be aware that getCount needs to be synchronized as well, since it is reading a value written by another thread.

External call to synchronized function held/locked

The Following class DoStuff starts a thread and syncs to protect the listener object from being accessed when null.
Now when accessing the DoStuff class function setOnProgressListener() externally I'm having issues because the call is getting held for a long time before it exits the function call. I'm not sure why this happens? I seems as if the synchronization has queued up a lot of calls? Any input on this would help!
I'm essentially passing null to the listener because I no longer wish to get updated for this status. I do this as part of my process to kill the DoStuff Thread.
Thanks!
public class DoStuff extends Runnable
{
Object MUTEX = new Object();
private OnProgressListener mOnProgressListener = null;
public DoStuff()
{
new Thread(this).start();
}
public void setOnProgressListener( OnProgressListener onProgressListener )
{
synchronized (MUTEX)
{
mOnProgressListener = onProgressListener;
}
}
private void reportStatus( int statusId )
{
synchronized (MUTEX)
{
if (null != mOnStatusListener)
{
mOnStatusListener.setStatusMessage(new OnStatusEvent(this, statusId));
}
}
}
// this is the run of a thread
public void run()
{
int status = 0;
do
{
// do some work and report the current work status
status = doWork();
reportStatus( status );
} while(true);
}
}
You should use wait/notify. here is sample;
public class DoStuff {
Object MUTEX = new Object();
String data = null;
public void setData(String data) {
synchronized (MUTEX) {
this.data = data;
System.out.println(Thread.currentThread());
MUTEX.notifyAll();
}
}
public void run() {
do {
synchronized (MUTEX) {
if (null == data) {
return;
} else {
System.out.println(data);
}
try {
MUTEX.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} while (true);
}
}
The trouble with this code is that your while() loop is constantly trying to grab the monitor for MUTEX immediately after releasing it or even yield()-ing to help the scheduler put another thread in. So there's a very good chance that anyone else trying to obtain that monitor will be starved, because your while() loop will consume most of your CPU time and even when other threads could run, they might not get the monitor they're waiting for.
Ideally a wait()/notify() pair should be used or failing that, you should at least call a Thread.yield() in your while loop, outside the synchronized block. (But I this second "solution" really isn't a very good one, you should consider using the first one instead.)
UPDATE: I read the code again and I think I believe to see what you wanted to achieve: printing the value of data every time you set a new value. If that's true, you should definitely go for the wait/notify solution, although if you want to absolutely guarantee that every single value is printed, you need to do even more work, possibly using a queue.
I'm a little confused about your code, can you provide the full listing?
First, where does DoStuff start a thread? Why are you quitting if your data is still null? (you might actually be out of the thread before setData even executes).
But the main thing here is that you're doing essentially a busy-waiting loop, in which you synchronize on the mutex. This is pretty wasteful and will generally block cores of your CPU.
Depending on what you are trying to do, you might want to use a wait-notify scheme, in which the thread goes to sleep until something happens.
Thanks all for your help. I was able to determine why the indefinite lock. Something important and obvious is that once I run the reportStatus() function call it will hold the lock MUTEX until it is completely done executing the callback. My fault was that at the registered callback I was calling setOnProgressListener(null) by mistake. Yes, I admit didn't post enough code, and most likely all of you would have catched the bug... So calling setOnProgressListener(null) would wait until the MUTEX object has been released, and the reportStatus() was held waiting to call setOnProgressListener(null), therefore I was in a deadlock!
Again the main point I learned is to remember that triggering a callback message will hold until the registered callback function is done processing it's call.
Thanks all!

Categories

Resources