EDIT: I'm assuming you meant Queue<Object> objectList
instead of ConcurrentLinkedQueue<Object> objectList
. ConcurrentLinkedQueue<Object>
already does all of your thread safety for you, meaning you can call objectList.peek()
all you want without worrying about race conditions. This is great if you're developing multi-threaded programs but not so great for learning about thread safety.
Your methods need not be synchronized
, assuming you have one thread operating on one instance of the object at a time, but however if you need to have multiple instances of the class that all refer to the same static class variable, you need to synchronized
over the class variable like so:
public static void getHeadObject() {
synchronized(safe.objectList) {
System.out.println(objectList.peek().toString());
}
}
This locks the objectList
and does not allow it to be read or written to in any other thread as soon as the program is inside the synchronization block. Do the same for all other methods to be synchronized
.
NOTE:
However, since you are doing only one simple get operation List.peek()
, you really don't need to synchronize over the objectList
since in a race condition, it'll get either one value of the List
or another. The problem with race conditions is when multiple complex read/write operations are performed, with the value changing in between them.
For example, if you had a class PairInt
with a PairInt.x
and PairInt.y
fields, with the constraint that x = 2y
, and you wanted to do
System.out.println(myIntPair.x.toString() + ", " + myIntPair.y.toString());
and another thread was updating the value of x
and y
at the same time,
myIntPair.y = y + 3;
myIntPair.x = 2 * y;
And the write thread modified myIntPair
in between your read thread's myIntPair.x.toString()
and myIntPair.y.toString()
you might get an output that looks like (10, 8)
, which means if you are operating on the assumption that x == 2 * y
could crash your program.
In that case, your read needs to use a synchronized
, but for more simpler things like peek()
on a simple object
that is being added or deleted, not modified while in the queue, the synchronized
can, in most cases be dropped. In fact, for string
, int
, bool
, and the like, the synchronized
condition for a simple read should be dropped.
However, writes should always be synchronized
on operations that are not explicitly thread safe, i.e. already handled by java. And as soon as you acquire more than one resource, or require that your resource stay the same throughout the operation as you do multiple lines of logic to it, then you MUST USE synchronized