Java Threading Unexpected Behavior - java

We have been looking at a threading error for a while and are not sure how this is possible. Below is a minimized example from our code. There is a cache holding data retrieved from a database (or: "a lengthy synchronous operation", as far as this example is concerned). There is a thread for reloading the cache, while other threads try to query the cache. There is a period of time when the cache is null, waiting to be reloaded. It should not be queryable during this time, and we tried to enforce this by synchronizing the methods that access the cache - both for reading and writing. Yet if you run this class for a while, you will get NPEs in search(). How is this possible?
Java docs state that "it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object".
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CacheMultithreading01 {
private long dt = 1000L;
public static void main(String[] args) {
CacheMultithreading01 cm = new CacheMultithreading01();
cm.demonstrateProblem();
}
void demonstrateProblem() {
QueryableCache cache = new QueryableCache();
runInLoop("Reload", new Runnable() {
#Override
public void run() {
cache.reload();
}
});
runInLoop("Search", new Runnable() {
#Override
public void run() {
cache.search(2);
}
});
// If the third "runInLoop" is commented out, no NPEs
runInLoop("_Clear", new Runnable() {
#Override
public void run() {
cache.clear();
}
});
}
void runInLoop(String threadName, Runnable r) {
new Thread(new Runnable() {
#Override
public synchronized void run() {
while (true) {
try {
r.run();
} catch (Exception e) {
log("Error");
e.printStackTrace();
}
}
}
}, threadName).start();
}
void log(String s) {
System.out.format("%d %s %s\n", System.currentTimeMillis(), Thread
.currentThread().getName(), s);
}
class QueryableCache {
private List<Integer> cache = new ArrayList<>();
public synchronized void reload() {
clear();
slowOp(); // simulate retrieval from database
cache = new ArrayList<>(Arrays.asList(1, 2, 3));
}
public synchronized void clear() {
cache = null;
}
public synchronized Integer search(Integer element) {
if (cache.contains(element))
return element;
else
return null;
}
private void slowOp() {
try {
Thread.sleep(dt);
} catch (InterruptedException e) {
}
}
}
}
//java.lang.NullPointerException
//at examples.multithreading.cache.CacheMultithreading01$QueryableCache.search(CacheMultithreading01.java:73)
//at examples.multithreading.cache.CacheMultithreading01$2.run(CacheMultithreading01.java:26)
//at examples.multithreading.cache.CacheMultithreading01$4.run(CacheMultithreading01.java:44)
//at java.lang.Thread.run(Thread.java:745)
We do not understand why the NPEs can happen even though the code is synchronized. We also do not understand why the NPEs stop happening if we comment out the third call to runInLoop (the one that does cache.clear).
We have also tried to implement locking using a ReentrantReadWriteLock - and the result is the same.

Since you don't have any more advanced locking, you can call clear() and search() consecutively. That will obviously cause a NPE.
Calling reload() and search() won't cause problems, since in reload the cache is cleared, then rebuilt, inside a synchronized block, preventing other (search) operations from being executed in between.
Why is there a clear() method that will leave cache in a "bad" state (which search() doesn't even check for)?

You have to check in the search method if cache is null. Otherwise calling contains on it in search can throw a NullPointerException in the case that you have previously set cache to null in the clear-method.

Synchronization is working as correctly.
The problem is that the method clear puts cache to null. And there is no guarantee that reload method will be called before search.
Also, note that the method reload, it's not releasing the lock. So, when you are waiting for the slowOp to finish, the other methods can't execute.

"There is a period of time when the cache is null, waiting to be reloaded."
This is your problem: clear sets things to null, and then returns, releasing the synchronization lock, allowing someone else to access.
It would be better to make the "new" assignment atomic and not clear().
Assuming that slowOp() needs to return data for the cache (private List<Integer> slowOp()) you retrieve that data before assigning it
ArrayList<Integer> waitingForData = slowOp();
cache = watingForData;
This 'updates' the cache only after the data is available. Assignment is an atomic operation, nothing can access cache while the reference is being updated.

Three different threads invoking clear() search() and reload() of the cache without a definitive interleaving. Since the interleaving doesn't gurantees the the sequence of lock being obtained for the clear() and search() threads there could be chances where the search thread is getting the lock over the object just after the clear() thread. In that case the search would result in the NullPointerException.
You may have to check for the cache equal to null in the search object and may be do a reload() from within the search() method. This would gurantee the search result or return null as applicable.

Related

The run method of Java thread does not take the updated status

The code below is my run method. This stat status does not take the newly updated status from my stop method.
#Override
public void run() {
synchronized (this) {
while (!stat) {
try {
this.wait();
} catch (InterruptedException ex) {
Logger.getLogger(TrafficLightSimulator.class.getName()).log(Level.SEVERE, null, ex);
} }
}
}
In the above code, the program does not enter while loop. It is because the stat boolean new changed value from the stop method is not taken in run method.
This is my new stop
public void stop() {
synchronized(this) {
this.stopStat = false;
this.notifyAll();
}
}
I even defined the stat as the volatile boolean variable. However, this also does not seem to work.
While you have the "waiting" part correct, your "setting" part is missing some important parts.
The first part that is missing is the lock:
public void stop() {
synchronized(this) {
this.stat = true;
}
}
This lock makes sure that only 1 thread can change/access it at the same time, as is required by the Java memory model. Without this lock (and without volatile), Java makes no guarantee that changes to this variable are seen by other threads.
The next part that missing is the notifying part, it is important to "wake" up all waiting threads when the condition is changed:
public void stop() {
synchronized(this) {
this.stat = true;
this.notifyAll();
}
}
The last part of your error happens due the fact you are setting the variable to true, while for the code to be inside the while loop, the variable is already true. You probably want to set it to false instead
public void stop() {
synchronized(this) {
this.stat = false;
this.notifyAll();
}
}
Memory visibility isn't an issue here because both the code reading the flag and the code setting the flag are synchronized, holding the same lock. If your code won't enter the while loop it must be that some other thread has the lock.
This is another reason (in addition to the reasons below) to use interrupt instead of wait/notify for this. Interruption doesn't depend on acquiring a lock to work.
Use interrupt for this instead. There's no good reason for your own flag here when one is provided for you, using wait/notify for this is unnecessary and can cause problems since you may need to wait/notify for other reasons.
The Java api docs advise against locking on threads, by the way. That's what join does. Implicit locking doesn't have a way to have different conditions get separate notifications for a lock (the way ReentrantLock does).
For a thread that does things with intermittent sleeps in between, the run method can look like:
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
doStuff();
Thread.sleep(1000L);
} catch (InterruptedException e) {
// no need to log this as an error, it's not an error
Thread.currentThread().interrupt();
}
}
}
Real world code uses threadpools where you submit Runnable or Callable tasks, the java.util.concurrent classes expect your code to handle interruption.

Thread safety when iterating through an ArrayList using foreach

I've got an ArrayList which is being instantiated and populated on the background thread (I use it to store the Cursor data). At the same time it can be accessed on the main thread and iterated through using foreach. So this obviously may result in throwing an exception.
My question is what's the best practice to make this class field thread-safe without copying it every time or using flags?
class SomeClass {
private final Context mContext;
private List<String> mList = null;
SomeClass(Context context) {
mContext = context;
}
public void populateList() {
new Thread(new Runnable() {
#Override
public void run() {
mList = new ArrayList<>();
Cursor cursor = mContext.getContentResolver().query(
DataProvider.CONTENT_URI, null, null, null, null);
try {
while (cursor.moveToNext()) {
mList.add(cursor.getString(cursor.getColumnIndex(DataProvider.NAME)));
}
} catch (Exception e) {
Log.e("Error", e.getMessage(), e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}).start();
}
public boolean searchList(String query) { // Invoked on the main thread
if (mList != null) {
for (String name : mList) {
if (name.equals(query) {
return true;
}
}
}
return false;
}
}
In general it is a very bad idea to operate concurrently on a datastructure that is not thread-safe. You have no guarantee that the implementation will not change in the future, which may severly impact the runtime behavior of the application, i.e. java.util.HashMap causes infinite loops when being concurrently modified.
For accessing a List concurrently, Java provides the java.util.concurrent.CopyOnWriteArrayList. Using this implementation will solve your problem in various ways:
it is thread safe, allowing concurrent modifications
iterating over snapshots of the list is not affected by concurrent add operations, allowing concurrently adding and iterating
it's faster than synchronization
Alternatively, if not using a copy of the internal array is a strict requirement (which I can't imagine in your case, the array is rather small as it only contains object references, which can be copied in memory quite efficiently), you may synchronize the access on the map.
But that would require the Map to be initialized properly, otherwise your code may throw a NullPointerException because the order of thread-execution is not guaranteed (you assume the populateList() is started before, so the list gets initialized.
When using a synchronized block, choose the protected block wisely. In case you have the entire content of the run() method in a synchronized block, the reader thread has to wait until the results from the cursor are processed - which may take a while - so you actually loose all concurrency.
If you decide to go for the synchronized block, I'd make the following changes (and I don't claim, they are perfectly correct):
Initialize the list field so we can synchronize access on it:
private List<String> mList = new ArrayList<>(); //initialize the field
Synchronize the modification operation (add). Do not read the data from the cursor inside the synchronization block because if its a low latency operation, the mList could not be read during that operation, blocking all other threads for quite a while.
//mList = new ArrayList<>(); remove that line in your code
String data = cursor.getString(cursor.getColumnIndex(DataProvider.NAME)); //do this before synchronized block!
synchronized(mList){
mList.add(data);
}
The read iteration must be inside the synchronization block, so no element gets added, while being iterated over:
synchronized(mList){
for (String name : mList) {
if (name.equals(query) {
return true;
}
}
}
So when two threads operate on the list, one thread can either add a single element or iterate over the entire list at a time. You have no parallel execution on these parts of the code.
Regarding the synchronized versions of a List (i.e. Vector, Collections.synchronizedList()). Those might be less performant because with synchronization you actually lose prallel execution as only one thread may run the protected blocks at a time. Further, they might still be prone to ConcurrentModificationException, which may even occur in a single thread. It is thrown, if the datastructure is modified between iterator creation and iterator should proceed. So those datastructures won't solve your problem.
I do not recommend manualy synchronization as well, because the risk of simply doing it wrong is too high (synchronizing on the wrong or different monitory, too large synchronization blocks, ...)
TL;DR
use a java.util.concurrent.CopyOnWriteArrayList
Use Collections.synchronizedList(new ArrayList<T>());
Ex:
Collections.synchronizedList(mList);
java synchronized block http://www.tutorialspoint.com/java/java_thread_synchronization.htm
class SomeClass {
private final Context mContext;
private List<String> mList = null;
SomeClass(Context context) {
mContext = context;
}
public void populateList() {
new Thread(new Runnable() {
#Override
public void run() {
synchronized(SomeClass.this){
mList = new ArrayList<>();
Cursor cursor = mContext.getContentResolver().query(
DataProvider.CONTENT_URI, null, null, null, null);
try {
while (cursor.moveToNext()) {
mList.add(cursor.getString(cursor.getColumnIndex(DataProvider.NAME)));
}
} catch (Exception e) {
Log.e("Error", e.getMessage(), e);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
}).start();
}
public boolean searchList(String query) { // Invoked on the main thread
synchronized(SomeClass.this){
if (mList != null) {
for (String name : mList) {
if (name.equals(query) {
return true;
}
}
}
return false;
}
}
}
You could use a Vector which is the thread-safe equivalent of ArrayList.
EDIT: Thanks to Fildor's comment, I now know this doesn't avoid ConcurrentModificationException from being thrown using multiple threads:
Only single calls will be synchronized. So one add cannot be called while another thread is calling add, for example. But altering the list will cause the CME be thrown while iterating on another thread. You can read the docs of iterator on that topic.
Also interesting:
Why is Java Vector class considered obsolete or deprecated?
Vector vs Collections.synchronizedList(ArrayList)
Long story short: DO NOT use Vector.

How do I stop mp3 files being played multiple times at once?

I am trying to play an mp3 file on button press or selection from a list (which I have managed successfully). However, I cannot seem to stop the song being played multiple times on the same button press.
What I would like to do is play the song in a new thread, disable playing the song again until the thread has closed, then allow playing again.
My code is as follows:
public class SoundFactory {
private Player player;
private static boolean running = false;
private String getFile(String name) {
String f = "sound" + File.separator + name + ".mp3";
return f;
}
public void playMP3(String name) {
if (!running) {
running = true;
try {
FileInputStream fis = new FileInputStream(getFile(name));
BufferedInputStream bis = new BufferedInputStream(fis);
player = new Player(bis);
} catch (Exception e) {
System.out.println("Problem playing file " + name);
System.out.println(e);
}
// run in new thread to play in background
new Thread() {
public void run() {
try {
player.play();
} catch (Exception e) {
System.out.println(e);
}
}
}.start();
//running = false;
}
}
public void close() {
if (player != null) player.close();
}
}
The file is played via:
SoundFactory sf = new SoundFactory();
sf.playMp3("song name");
on a JButton click
I am new to threading so I apologise in advance if this has an obvious solution!
It sounds to me like you are getting multiple click events fired at once instead of just one. A little logging should verify this. Your method as is, is wide open to race conditions.
The two events can be so close together that when the one checks running it see !running as true. Before that one can do running = true, the second event also sees !running as true and enters the if clause. They then both set running to true and spawn a thread to play the mp3.
What you need to do is make your method synchronized.
public synchronized void playMP3(String name)
http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
If count is an instance of SynchronizedCounter, then making these
methods synchronized has two effects:
First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing
a synchronized method for an object, all other threads that invoke
synchronized methods for the same object block (suspend execution)
until the first thread is done with the object.
Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent
invocation of a synchronized method for the same object. This
guarantees that changes to the state of the object are visible to all
threads.
Just to clarify my last comment, here is a test program showing where running = false should be placed.
public class Test {
public static boolean running = false;
public synchronized void runner() {
if(!running) {
running = true;
System.out.println("I'm running!");
new Thread() {
public void run() {
for(int i=0; i<10000; i++) {} // Waste some time
running = false; // This is only changed once the thread completes its execution.
}
}.start();
} else {
System.out.println("Already running.");
}
}
public static void main(String[] args) {
Test tester = new Test();
tester.runner();
tester.runner(); // The loop inside the Thread should still be running so this should fail.
for(int i=0; i<20000; i++) {} // Waste even more time.
tester.runner(); // The loop inside the Thread should be done so this will work.
}
}
It outputs:
I'm running!
Already running.
I'm running!
It's been years since I've worked with Swing and had forgotten that its event dispatcher is single threaded. So your issue is more likely this than a race condition. It still doesn't hurt to get into writing things to be thread safe from the beginning as it gets you used to it and thinking that way.
Definite warning on using the synchronized method... It can be horrible on performance if only a small part of your method needs to be synchronized. In this case your whole method needs to be thread safe.
If only a small part needs to be thread safe you need to use synchronized blocks.
Thread safe per instance:
public class myClass {
public void myFunc() {
// bunch of code that doesn't need to be thread safe.
synchronized(this) {
// Code that needs to be thread safe per instance
}
// More code that doesn't need thread safety.
}
}
Thread safe across all instances.
public class myClass {
static Object lock = new Object();
public void myFunc() {
// bunch of code that doesn't need to be thread safe.
synchronized(lock) {
// Code that needs to be thread safe across all instances.
}
// More code that doesn't need thread safety.
}
}
Thread safe in a static method.
public class myClass {
public static void myFunc() {
// bunch of code that doesn't need to be thread safe.
synchronized(MyClass.class) {
// Code that needs to be thread safe.
}
// More code that doesn't need thread safety.
}
}
Probably way more information than you want, but I've just seen threaded programming taught so poorly many, many times.
You need to call JButton.setEnabled(false); right before you start playing the mp3, and then call JButton.setEnabled(true); when the mp3 finishes playing.
Obviously, you should replace JButton with your button's object (eg: playButton.setEnabled()).

Can it be acceptable in Java to use Thread#stop() to kill a thread that is running wild?

Regrettably there is no way to specify a timeout when using a regular expression on a String in Java. So if you have no strict control over what patterns get applied to which input, you might end up having threads that consume a lot of CPU while endlessly trying to match (not so well designed) patterns to (malicious?) input.
I'm aware of the reasons why Thread#stop() is deprecated (see http://download.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html). They are centered around objects that might get damaged in case of ThreadDeath exceptions, and which then pollute your running JVM environment and can lead to subtle errors.
My question to anyone who has deeper insight than me into the workings of the JVM is this: If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?
I created a rather defensive solution to be able to process regular expression matching with a timeout. I would be glad for any comment or remark, especially on problems that this approach can cause despite my efforts to avoid them.
Thanks!
import java.util.concurrent.Callable;
public class SafeRegularExpressionMatcher {
// demonstrates behavior for regular expression running into catastrophic backtracking for given input
public static void main(String[] args) {
SafeRegularExpressionMatcher matcher = new SafeRegularExpressionMatcher(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "(x+x+)+y", 2000);
System.out.println(matcher.matches());
}
final String stringToMatch;
final String regularExpression;
final int timeoutMillis;
public SafeRegularExpressionMatcher(String stringToMatch, String regularExpression, int timeoutMillis) {
this.stringToMatch = stringToMatch;
this.regularExpression = regularExpression;
this.timeoutMillis = timeoutMillis;
}
public Boolean matches() {
CallableThread<Boolean> thread = createSafeRegularExpressionMatchingThread();
Boolean result = tryToGetResultFromThreadWithTimeout(thread);
return result;
}
private CallableThread<Boolean> createSafeRegularExpressionMatchingThread() {
final String stringToMatchForUseInThread = new String(stringToMatch);
final String regularExpressionForUseInThread = new String(regularExpression);
Callable<Boolean> callable = createRegularExpressionMatchingCallable(stringToMatchForUseInThread,
regularExpressionForUseInThread);
CallableThread<Boolean> thread = new CallableThread<Boolean>(callable);
return thread;
}
private Callable<Boolean> createRegularExpressionMatchingCallable(final String stringToMatchForUseInThread,
final String regularExpressionForUseInThread) {
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return Boolean.valueOf(stringToMatchForUseInThread.matches(regularExpressionForUseInThread));
}
};
return callable;
}
private Boolean tryToGetResultFromThreadWithTimeout(CallableThread<Boolean> thread) {
startThreadAndApplyTimeout(thread);
Boolean result = processThreadResult(thread);
return result;
}
private void startThreadAndApplyTimeout(CallableThread<Boolean> thread) {
thread.start();
try {
thread.join(timeoutMillis);
} catch (InterruptedException e) {
throwRuntimeException("Interrupt", e);
}
}
private Boolean processThreadResult(CallableThread<Boolean> thread) {
Boolean result = null;
if (thread.isAlive()) {
killThread(thread); // do not use anything from the thread anymore, objects may be damaged!
throwRuntimeException("Timeout", null);
} else {
Exception exceptionOccurredInThread = thread.getException();
if (exceptionOccurredInThread != null) {
throwRuntimeException("Exception", exceptionOccurredInThread);
} else {
result = thread.getResult();
}
}
return result;
}
private void throwRuntimeException(String situation, Exception e) {
throw new RuntimeException(situation + " occured while applying pattern /" + regularExpression + "/ to input '"
+ stringToMatch + " after " + timeoutMillis + "ms!", e);
}
/**
* This method uses {#link Thread#stop()} to kill a thread that is running wild. Although it is acknowledged that
* {#link Thread#stop()} is inherently unsafe, the assumption is that the thread to kill does not hold any monitors on or
* even references to objects referenced by the rest of the JVM, so it is acceptable to do this.
*
* After calling this method nothing from the thread should be used anymore!
*
* #param thread Thread to stop
*/
#SuppressWarnings("deprecation")
private static void killThread(CallableThread<Boolean> thread) {
thread.stop();
}
private static class CallableThread<V> extends Thread {
private final Callable<V> callable;
private V result = null;
private Exception exception = null;
public CallableThread(Callable<V> callable) {
this.callable = callable;
}
#Override
public void run() {
try {
V result = compute();
setResult(result);
} catch (Exception e) {
exception = e;
} catch (ThreadDeath e) {
cleanup();
}
}
private V compute() throws Exception {
return callable.call();
}
private synchronized void cleanup() {
result = null;
}
private synchronized void setResult(V result) {
this.result = result;
}
public synchronized V getResult() {
return result;
}
public synchronized Exception getException() {
return exception;
}
}
}
EDIT:
Thanks to dawce who pointed me to this solution I have been able to solve my original problem without the need for additional threads. I have posted the code there. Thanks to all who have responded.
You can use Thread.stop() if you determine its the only solution available to you. You may need to shutdown and restart your applicaton to ensure its in a good state.
Note: a Thread can capture and ignore ThreadDeath so stop isn't guarenteed to stop all threads.
An alternative way to stop a thread is to run it in a different process. This can be killed as required. This can still leave resources in an incosistent state (like lock files) but it is less likely and easier to control.
The best solution of course is to fix the code so it doesn't do this in the first place and respects Thread.interrupt() instead.
Instead of using Thread.stop() which is deprecated, use Thread.interrupt() which will stop raise the interrupt flag which can be checked via isInterrupted() or interrupted(), or throws an InterruptedException.
My pattern for building extending the Thread class is like this
class MyThread extends Thread{
private volatile boolean keepRunning = true;
public void run(){
while(keepRunning){
// do my work
}
}
public void killThread(){
keepRunning = false;
this.interrupt();
}
}
I'm not saying my way of handling it is perfect, there may bet better, but this works for me.
If the thread that needs to be stopped does not hold any (obvious) monitors on or references to objects that are used by the rest of the program, can it then be acceptable to use Thread#stop() nevertheless?
It is up to you to decide if it is "acceptable". All we can do is to advise on whether it is safe. And the answer is that it isn't.
what about the non-obvious monitors and references that it holds?
what about notifies, etc that it would otherwise make?
what about actions that it might otherwise make affecting statics?
The problem is that it is difficult (in most cases) to know for sure that you've considered all of the possible interactions that the thread might have with the rest of the application.
Restarting the application is exactly what I try to avoid ...
It strikes me that that is the real root of your problem; i.e. you've designed a program without taking account of the fact that long-running programs need to be restarted for pragmatic reasons. Especially complicated ones that have potential bugs.
If you specifically design your thread code to not hold locks etc., (yes, and this includes the non-explicit locks. eg. a malloc lock that may be used when changing string sizes), then stop the thread, yes. Polling an 'interrupted' flag is fine, except that it means polling an 'interrupted' flag, ie. overhead during the 99.9999% of the time it is not actually set. This can be an issue with high-performance, tight loops.
If the check can be kept out of an innermost loop and still be checked reasonably frequently, then that is indeed the best way to go.
If the flag cannot be checked often, (eg. because of a tight loop in inaccessible library code), you could set the thread priority to the lowest possible and forget it until it does eventually die.
Another bodge that is occasionally possible is to destroy the data upon which the thread is working in such a way that the library code does exit normally, causes an exception to be raised and so control bubbles out of the opaque library code or causes an 'OnError' handler to be called. If the lib. is operating on a string, splatting the string with nulls is sure to do something. Any exception will do - if you can arrange for an AV/segfault in the thread, then fine, as long as you get control back.

Synchronized functions in Java

I have a class with a function which is synchronized like so:
public synchronized void enqueue(int number) {...}
In my program I have several threads running all wanting to use this function on a specific object of the class. What I would like to happen is for the threads to simply try using the function and if it is locked to not wait on it simply skip running that function.
Can this be done without using the Java.util.concurency library and only using syncronization primatives?
The restriction of not using concurrency is not optional
I like the AtomicInteger solution, but of course AtomicInteger is part of the concurrency package. You can follow the same principle (with lower efficiency, though) with the following simple code:
private boolean locked = false;
public void enqueue(int number) {
synchronized (this) {
if (locked) {
return;
}
locked = true;
}
try {
// Synchronized goodness goes here.
} finally {
synchronized (this) {
locked = false;
}
}
}
Since you're restricted here, here's what I would do:
Make a class with the ability to tell it that you want to lock on it. There are two types of locks: passive lock, and active lock. A passive lock will allow an unlimited number of threads to pass. An active lock will make it belong only to that thread.
When you want a passive lock, you have to register yourself, and unregister yourself when you're done. You'll wait on an internal object until all active locks are done.
When you want an active lock, you wait for all current passive locks have unregistered. If there's currently an active lock (store a thread reference to see if there is, utilizing Thread.currentThread()) then wait until notified. You can then set yourself as the referred thread. When you unregister, if there are waiting active locks, notify one of them (consider a Set<Thread> to register this). If there aren't, notify all the passive locks that are waiting and they can go through.
There's going to be a lot of unanswered questions here, and I doubt it's perfect, but this is most of what you're looking for...
Rather than use any synchronization primitives I'd recommend using something like the AtomicInteger class to leverage a CAS (compare-and-swap) operation for your anti-concurrency strategy:
public void enqueue(int number) {
if (!atomicInteger.compareAndSet(0, 1) {
return;
}
try {
// Synchronized goodness goes here.
} finally {
atomicInteger.set(0);
}
}
May be you can you synchronize the object that handles the Queue. If someone else ois using the queue the enqueue does nothing. I have an example that compiles and run. Very simple example but not pretty:
class Queue {
public void enqueue(int number) {
// something in this method for demo purposes only
try {
Thread.sleep(100);
} catch (InterruptedException e){}
System.out.println(Thread.currentThread().getName()+" done");
}
}
class Demo {
private static Queue e = new Queue();
public void enqueue(int number) {
Queue q = getQueue();
if (q!=null) {
q.enqueue(number);
releaseQueue(q);
} else {
// do nothing since the queue is being used
System.out.println(Thread.currentThread().getName()+" done doing nothing");
}
}
public synchronized Queue getQueue() {
Queue b = e;
e = null;
return b;
}
public synchronized void releaseQueue(Queue q) {
e = q;
}
public static void main(String[] args) {
for (int j = 0; j < 5; j++) {
Thread t = new Thread(new Runnable() {
public void run() {
Demo d = new Demo();
d.enqueue(5);
}
}, "Thread "+j);
t.start();
try {
Thread.sleep(50);
} catch (InterruptedException e){}
}
}
}
YES You can implement locking on your own by managing a static variable in that class, or a using a "lock" text file, for example.
HOWEVER Although this simplistic hack would not be terribly difficult --- the java.util.concurrency package solution would be EVEN EASIER, AND is a better choice because, as you will quickly find, when building multithreaded resources into applications our needs will quickly exceed your current expectations
Don't worry about the WHOLE concurrency package -- I find that just taking 3 minutes to learn how to use the AtomicBoolean or AtomicLong fields can be enough to enable simple, multithreaded logic with a minimal effort.

Categories

Resources