Is there a possibility that HashSet could have duplicate values in case of multiple threads adding items to it?
I'm not looking from modifying the equals or hashcode methods perspective but simply from multithreaded environment.
Is there a possibility that HashSet could have duplicate values in case of multiple threads adding items to it?
HashSet is not a thread-safe class. If you update a HashSet from multiple threads without proper synchronization, then the behavior is unspecified, and difficult to predict. (And Java version dependent, given that the implementation of HashSet has changed a number of times over the lifetime of Java SE.)
The unspecified behavior could include duplicates appearing in the set as observed via the set's iterator.
If you want to share a (mutable) set between multiple threads, either use a ConcurrentHashSet or a Collections.synchronizedSet wrapper or an explicit Lock or mutex to synchronize operations.
(The different alternatives all have caveats associated with them. We can't recommend a specific alternative based on the limited information you have given.)
We can discuss this answer part by part:
HashSet does not allow duplicate elements which means you can not store duplicate values in HashSet. And its alternative Hashmap doesn't allow duplicate keys however, it allows duplicate values.
HashSet in Java is not thread-safe as it is not synchronized by default. If you are using HashSet in a multi-threaded environment where it is accessed by multiple threads concurrently and structurally modified too by even a single thread then it must be synchronized externally. A structural modification is defined as any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.
So, when you update HashSet from multiple threads without external sync, its behavior will be unpredictable.
To avoid this unpredictable behavior, we can synchronize HashSet by using Collections.synchronizedSet() method.
Example:
First, we’ll see an example what happens if HashSet is used in a multi-threaded environment without synchronizing it.
In the Java code four threads are created, each of these thread adds 5 elements to the Set. After all the threads are done Set size should be 20.
public class SetSynchro implements Runnable{
private Set<String> numSet;
public SetSynchro(Set<String> numSet){
this.numSet = numSet;
}
public static void main(String[] args) {
Set<String> numSet = new HashSet<String>();
/// 4 threads
Thread t1 = new Thread(new SetSynchro(numSet));
Thread t2 = new Thread(new SetSynchro(numSet));
Thread t3 = new Thread(new SetSynchro(numSet));
Thread t4 = new Thread(new SetSynchro(numSet));
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Size of Set is " + numSet.size());
}
#Override
public void run() {
System.out.println("in run method" + Thread.currentThread().getName());
String str = Thread.currentThread().getName();
for(int i = 0; i < 5; i++){
// adding thread name to make element unique
numSet.add(i + str);
try {
// delay to verify thread interference
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Output:
in run methodThread-2
in run methodThread-0
in run methodThread-3
in run methodThread-1
Size of Set is 19
//In one of the run size was 19, in another run 18 and sometimes even 20, so you can see that thread interference is making the behavior unpredictable.
So you can see that thread interference is making the behavior unpredictable. So we’ll synchronize the HashSet using the same example.
public class SetSynchro implements Runnable{
private Set<String> numSet;
public SetSynchro(Set<String> numSet){
this.numSet = numSet;
}
public static void main(String[] args) {
// Synchronized Set
Set<String> numSet = Collections.synchronizedSet(new HashSet<String>());
/// 4 threads
Thread t1 = new Thread(new SetSynchro(numSet));
Thread t2 = new Thread(new SetSynchro(numSet));
Thread t3 = new Thread(new SetSynchro(numSet));
Thread t4 = new Thread(new SetSynchro(numSet));
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Size of Set is " + numSet.size());
}
#Override
public void run() {
System.out.println("in run method" + Thread.currentThread().getName());
String str = Thread.currentThread().getName();
for(int i = 0; i < 5; i++){
// adding thread name to make element unique
numSet.add(i + str);
try {
// delay to verify thread interference
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Output:
in run methodThread-3
in run methodThread-2
in run methodThread-1
in run methodThread-0
Size of Set is 20
//Now every time size of HashSet is 20.
For more details, this link is useful. The code block is also taken from there.
From Javadoc
Note that this implementation is not synchronized. If multiple threads
access a hash set concurrently, and at least one of the threads
modifies the set, it must be synchronized externally. This is
typically accomplished by synchronizing on some object that naturally
encapsulates the set. If no such object exists, the set should be
"wrapped" using the Collections.synchronizedSet method. This is best
done at creation time, to prevent accidental unsynchronized access to
the set:
Set s = Collections.synchronizedSet(new HashSet(...));
Basically, the way that I interpret this, is that under the right (or wrong) conditions, there might be a slight possibility that this could happen. HOWEVER, since the assumption is that you know that multiple threads will access this set, you need to synchronize access externally (since HashSet is not thread-safe). OR, in the absence of such external mechanism, you will need to wrap this set as shown above.
If you really want to find out, create an application with a lot of threads that attempt to set the same value. After insertion, print out some message to the console if the size of the set is ever greater than 1. That should tell you the answer. Maybe the chances of this happening are very small. But the class documentation tells you that if you expect to use in multithreaded process, you should synchronize it.
Related
===update====
from comment
so I clearly read the doc and know it's not thread safe and I wanted to run a small experiment to see how it will break. So the doc says the result is non deterministic. Does anyone know what could happen? If I want to prove it's not thread safe how can I write a sample code so that I can actually see that it's no thread safe? Have you guys actually tried and seen not working example? Do you have sample code?
If I have three threads accessing the hashset of string.
One adding a new string
Second removing the string
Third removing all
Is the HashSet thread safe?
public void test()
{
Set<String> test = new HashSet<>();
Thread t0= new Thread(new Runnable() {
#Override
public void run() {
while (true) {
boolean c = test.contains("test");
System.out.println("checking " + c);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
test.add("test");
System.out.println("adding");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
if (!test.isEmpty())
{
test.removeAll(test);
}
System.out.println("removing");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t0.start();
t1.start();
t2.start();
while(true) {
}
}
I have this test code and ran it and it seems working. No exceptions were thrown. I was little confused because HashSet is not thread-safe.
Whay am I missing?
From comment:
so I clearly read the doc and know it's not thread safe and I wanted to run a small experiment to see how it will break. So the doc says the result is non deterministic. does anyone know what could happen? If I want to prove it's not thread how cam I write a sample code so that I can actually see that it's no thread safe? Have you guys actually tried and seen that not working example? do you have sample code?
The problem is that updating the Set may not be an atomic operation, especially not when the internal hash table needs to be re-sized.
If two threads are updating at the same time, you may get the simple result that one thread overrides the change by the other thread, so you lose a change. More seriously, the conflict may corrupt the internal structure of the Set.
To show this, here is a small program that causes high conflict during add of values. All values added are distinct, so they should all be added, but you will see that size of the Set is incorrect when program is done, proving that some added values got lost.
final int THREAD_COUNT = 10;
final int NUMS_TO_ADD = 100000;
Set<Integer> set = new HashSet<>();
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
final int threadNo = i;
threads[i] = new Thread() {
#Override public void run() {
for (int j = 0; j < NUMS_TO_ADD; j++)
set.add(j * THREAD_COUNT + threadNo); // all distinct values
}
};
threads[i].start();
}
for (int i = 0; i < threads.length; i++)
threads[i].join();
System.out.println("Found " + set.size() + " values, expected " + THREAD_COUNT * NUMS_TO_ADD);
Each time you run it, you will get a different result, e.g.
Found 898070 values, expected 1000000
Found 825773 values, expected 1000000
Found 731886 values, expected 1000000
Exception in thread "Thread-7" java.lang.ClassCastException: java.base/java.util.HashMap$Node cannot be cast to java.base/java.util.HashMap$TreeNode
at java.base/java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1883)
at java.base/java.util.HashMap$TreeNode.putTreeVal(HashMap.java:2063)
at java.base/java.util.HashMap.putVal(HashMap.java:638)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.add(HashSet.java:220)
at Test$1.run(Test.java:16)
Or the program simply hangs!
Thread Safe
Thread unsafe does not mean you can not use it in multi-treads or the program will throw exceptions. It means you can not always get what you want when program is executed in multi threads. See this for more.
In computer programming, thread-safe describes a program portion or
routine that can be called from multiple programming threads without
unwanted interaction between the threads.
And, you can not say an object is thread safe even if you get the expected experiment results. Because the results may vary in different environments. You should use synchronization mechanism provided by JDK.
HashSet
HashSet is not thread safe, this means:
If you write an object into it, this object may not be visible to
other threads.
If you read the set from different threads at same time, they may get different results.
If you call add first, then call removeAll, the objects in this
set may not be removed.
......
User Andreas's example is pretty clear. Since HashSet is based on HashMap's key set, you can refer this How to prove that HashMap in java is not thread-safe.
Solution
JDK provided a thread safe version set, all operations on the set need aquire a inner monitor lock first.
Set s = Collections.synchronizedSet(new HashSet(...));
we have two threads accessing one list via a synchronized method. Can we
a) rely on the run time to make sure that each of them will receive access to the method based on the order they tried to or
b) does the VM follow any other rules
c) is there a better way to serialize the requests?
No, synchronized will give access in any order (Depends on the JVM implementation). This could even cause Threads to starve in some scenarios.
You can ensure the order by using ReentrantLock (since Java 5.0) with the fair=true option. (Lock lock = new ReentrantLock(true);)
No you cannot be sure that two calls to a synchronized method will occur in order. The order is unspecified and implementation dependent.
This is defined in the 17.1 Locks section of the JLS. Notice that is says nothing about the order in which threads waiting on a lock should gain access.
You can't rely on the order in which the particular method is called from each threads. If it is only two threads may be yes. But imagine if there are 3 threads and 1 thread already acquired access. The other 2 threads when they try to access will wait and any one of them can be awarded the access, and this does not depend on the order in which they called this method.
So, it is not suggested to rely on the order.
c) is there a better way to serialize the requests?
Are you by any chance using the list as a queue, i.e., does the usage pattern look something like this?
while (some condition) {
synchronized(theList){
anItem = get and remove an element from theList
}
do some work with anItem
}
If so, you may want to look at the BlockingQueue interface instead of using your own locking schemes. The implementations (like ArrayBlockingQueue) have settings for fairness and more.
I always leave syncs to app server or engine unless defining own intensity
I have solved similar problem with couple of instrument. The problem I was trying to solve is Ping Pong Service. two thread one prints Ping and the other prints Pong. but They have to be SEQUENTIAL. (no double Ping or double Pong)
I will put one of the Implementation here but you can have a look other implementation (6 or 7 different way for now)
https://github.com/tugrulkarakaya/pingpong
import java.util.concurrent.*;
public class Method2CyclicBarrier {
ExecutorService service;
CyclicBarrier c1 = new CyclicBarrier(2);
CyclicBarrier c2 = new CyclicBarrier(2);
public static void main(String[] args) {
Method2CyclicBarrier m = new Method2CyclicBarrier();
m.runPingPong();
}
public void runPingPong(){
service = Executors.newFixedThreadPool(2);
service.submit(() -> this.printPing(c1, c2));
service.submit(() -> this.printPong(c1, c2));
}
public void printPing(CyclicBarrier c1, CyclicBarrier c2) {
while(!Thread.currentThread().isInterrupted()) {
try {
c1.await();
System.out.println("PING");
c2.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
catch(BrokenBarrierException ex){
}
}
}
public void printPong(CyclicBarrier c1, CyclicBarrier c2){
while(!Thread.currentThread().isInterrupted()) {
try {
c1.await();
c2.await();
System.out.println("PONG");
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch(BrokenBarrierException ex){
}
}
}
}
Yes.
If access to the list is via one synchronized method, concurrent requests from multiple threads will be serialized.
What are the possible ways to make code thread-safe without using the synchronized keyword?
Actually, lots of ways:
No need for synchronization at all if you don't have mutable state.
No need for synchronization if the mutable state is confined to a single thread. This can be done by using local variables or java.lang.ThreadLocal.
You can also use built-in synchronizers. java.util.concurrent.locks.ReentrantLock has the same functionality as the lock you access when using synchronized blocks and methods, and it is even more powerful.
Only have variables/references local to methods. Or ensure that any instance variables are immutable.
You can make your code thread-safe by making all the data immutable, if there is no mutability, everything is thread-safe.
Secondly, you may want to have a look at java concurrent API which has provision for providing read / write locks which perform better in case there are lots of readers and a few writers. Pure synchronized keyword will block two readers also.
////////////FIRST METHOD USING SINGLE boolean//////////////
public class ThreadTest implements Runnable {
ThreadTest() {
Log.i("Ayaz", "Constructor..");
}
private boolean lockBoolean = false;
public void run() {
Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName());
while (lockBoolean) {
// infinite loop for other thread if one is accessing
}
lockBoolean = true;
synchronizedMethod();
}
/**
* This method is synchronized without using synchronized keyword
*/
public void synchronizedMethod() {
Log.e("Ayaz", "processing...." + Thread.currentThread().getName());
try {
Thread.currentThread().sleep(3000);
} catch (Exception e) {
System.out.println("Exp");
}
Log.e("Ayaz", "complete.." + Thread.currentThread().getName());
lockBoolean = false;
}
} //end of ThreadTest class
//For testing use below line in main method or in Activity
ThreadTest threadTest = new ThreadTest();
Thread threadA = new Thread(threadTest, "A thead");
Thread threadB = new Thread(threadTest, "B thead");
threadA.start();
threadB.start();
///////////SECOND METHOD USING TWO boolean/////////////////
public class ThreadTest implements Runnable {
ThreadTest() {
Log.i("Ayaz", "Constructor..");
}
private boolean isAnyThreadInUse = false;
private boolean lockBoolean = false;
public void run() {
Log.i("Ayaz", "Thread started.." + Thread.currentThread().getName());
while (!lockBoolean)
if (!isAnyThreadInUse) {
isAnyThreadInUse = true;
synchronizedMethod();
lockBoolean = true;
}
}
/**
* This method is synchronized without using synchronized keyword
*/
public void synchronizedMethod() {
Log.e("Ayaz", "processing...." + Thread.currentThread().getName());
try {
Thread.currentThread().sleep(3000);
} catch (Exception e) {
System.out.println("Exp");
}
Log.e("Ayaz", "complete.." + Thread.currentThread().getName());
isAnyThreadInUse = false;
}
} // end of ThreadTest class
//For testing use below line in main method or in Activity
ThreadTest threadTest = new ThreadTest();
Thread t1 = new Thread(threadTest, "a thead");
Thread t2 = new Thread(threadTest, "b thead");
t1.start();
t2.start();
To maintain predictability you must either ensure all access to mutable data is made sequentially or handle the issues caused by parallel access.
The most gross protection uses the synchronized keyword. Beyond that there are at least two layers of possibility, each with their benefits.
Locks/Semaphores
These can be very effective. For example, if you have a structure that is read by many threads but only updated by one you may find a ReadWriteLock useful.
Locks can be much more efficient if you choose your lock to match the algorithm.
Atomics
Use of AtomicReference for example can often provide completely lock free functionality. This can usually provide huge benefits.
The reasoning behind atomics is to allow them to fail but to tell you they failed in a way you can handle it.
For example, if you want to change a value you can read it and then write its new value so long as it is still the old value. This is called a "compare and set" or cas and can usually be implemented in hardware and so is extremely efficient. All you then need is something like:
long old = atomic.get();
while ( !atomic.cas(old, old+1) ) {
// The value changed between my get and the cas. Get it again.
old = atomic.get();
}
Note, however, that predictability is not always the requirement.
Well there are many ways you can achieve this, but each contains many flavors. Java 8 also ships with new concurrency features.
Some ways you could make sure thread safety are:
Semaphores
Locks-Reentrantlock,ReadWriteLock,StampedLock(Java 8)
Why do u need to do it?
Using only local variable/references will not solve most of the complex business needs.
Also, if instance variable are immutable, their references can still be changed by other threads.
One option is use something like a SingleThreadModel, but it is highly discouraged and deprecated.
u can also look at concurrent api as suggested above by Kal
In a legacy application I have a Vector that keeps a chronological list of files to process and multiple threads ask it for the next file to process. (Note that I realize that there are likely better collections to use (feel free to suggest), but I don't have time for a change of that magnitude right now.)
At a scheduled interval, another thread checks the working directory to see if any files appear to have been orphaned because something went wrong. The method called by this thread occasionally throws a ConcurrentModificationException if the system is abnormally busy. So I know that at least two threads are trying to use the Vector at once.
Here is the code. I believe the issue is the use of the clone() on the returned Vector.
private synchronized boolean isFileInDataStore( File fileToCheck ){
boolean inFile = false;
for( File wf : (Vector<File>)m_dataStore.getFileList().clone() ){
File zipName = new File( Tools.replaceFileExtension(fileToCheck.getAbsolutePath(), ZIP_EXTENSION) );
if(wf.getAbsolutePath().equals(zipName.getAbsolutePath()) ){
inFile = true;
break;
}
}
return inFile;
}
The getFileList() method is as follows:
public synchronized Vector<File> getFileList() {
synchronized(fileList){
return fileList;
}
}
As a quick fix, would changing the getFileList method to return a copy of the vector as follows suffice?
public synchronized Vector<File> getFileListCopy() {
synchronized(fileList){
return (Vector<File>)fileList.clone();
}
}
I must admit that I am generally confused by the use of synchronized in Java as it pertains to collections, as simply declaring the method as such is not enough. As a bonus question, is declaring the method as synchronized and wrapping the return call with another synchronized block just crazy coding? Looks redundant.
EDIT: Here are the other methods which touch the list.
public synchronized boolean addFile(File aFile) {
boolean added = false;
synchronized(fileList){
if( !fileList.contains(aFile) ){
added = fileList.add(aFile);
}
}
notifyAll();
return added;
}
public synchronized void removeFile( File dirToImport, File aFile ) {
if(aFile!=null){
synchronized(fileList){
fileList.remove(aFile);
}
// Create a dummy list so I can synchronize it.
List<File> zipFiles = new ArrayList<File>();
synchronized(zipFiles){
// Populate with actual list
zipFiles = (List<File>)diodeTable.get(dirToImport);
if(zipFiles!=null){
zipFiles.remove(aFile);
// Repopulate list if the number falls below the number of importer threads.
if( zipFiles.size()<importerThreadCount ){
diodeTable.put(dirToImport, getFileList( dirToImport ));
}
}
}
notifyAll();
}
}
Basically, there are two separate issues here: sycnhronization and ConcurrentModificationException. Vector in contrast to e.g. ArrayList is synchronized internally so basic operation like add() or get() do not need synchronization. But you can get ConcurrentModificationException even from a single thread if you are iterating over a Vector and modify it in the meantime, e.g. by inserting an element. So, if you performed a modifying operation inside your for loop, you could break the Vector even with a single thread. Now, if you return your Vector outside of your class, you don't prevent anyone from modifyuing it without proper synchronization in their code. Synchronization on fileList in the original version of getFileList() is pointless. Returning a copy instead of original could help, as could using a collection which allows modification while iterating, like CopyOnWriteArrayList (but do note the additional cost of modifications, it may be a showstopper in some cases).
"I am generally confused by the use of synchronized in Java as it
pertains to collections, as simply declaring the method as such is not
enough"
Correct. synchronized on a method means that only one thread at a time may enter the method. But if the same collection is visible from multiple methods, then this doesn't help much.
To prevent two threads accessing the same collection at the same time, they need to synchronize on the same object - e.g. the collection itself. You have done this in some of your methods, but isFileInDataStore appears to access a collection returned by getFileList without synchronizing on it.
Note that obtaining the collection in a synchronized manner, as you have done in getFileList, isn't enough - it's the accessing that needs synchronizing. Cloning the collection would (probably) fix the issue if you only need read-access.
As well as looking at synchronizing, I suggest you track down which threads are involved - e.g. print out the call stack of the exception and/or use a debugger. It's better to really understand what's going on than to just synchronize and clone until the errors go away!
Where does the m_dataStore get updated? That's a likely culprit if it's not synchronized.
First, you should move your logic to whatever class is m_dataStore if you haven't.
Once you've done that, make your list final, and synchronize on it ONLY if you are modifying its elements. Threads that only need to read it, don't need synchronized access. They may end up polling an outdated list, but I suppose that is not a problem. This gets you increased performance.
As far as I can tell, you would only need to synchronize when adding and removing, and only need to lock your list.
e.g.
package answer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Example {
public static void main(String[] args)
{
Example c = new Example();
c.runit();
}
public void runit()
{
Thread.currentThread().setName("Thread-1");
new Thread("Thread-2")
{
#Override
public void run() {
test1(true);
}
}.start();
// Force a scenario where Thread-1 allows Thread-2 to acquire the lock
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
}
// At this point, Thread-2 has acquired the lock, but it has entered its wait() method, releasing the lock
test1(false);
}
public synchronized void test1(boolean wait)
{
System.out.println( Thread.currentThread().getName() + " : Starting...");
try {
if (wait)
{
// Apparently the current thread is supposed to wait for some other thread to do something...
wait();
} else {
// The current thread is supposed to keep running with the lock
doSomeWorkThatRequiresALockLikeRemoveOrAdd();
System.out.println( Thread.currentThread().getName() + " : Our work is done. About to wake up the other thread(s) in 2s...");
Thread.sleep(2000);
// Tell Thread-2 that it we have done our work and that they don't have to spare the CPU anymore.
// This essentially tells it "hey don't wait anymore, start checking if you can get the lock"
// Try commenting this line and you will see that Thread-2 never wakes up...
notifyAll();
// This should show you that Thread-1 will still have the lock at this point (even after calling notifyAll).
//Thread-2 will not print "after wait/notify" for as long as Thread-1 is running this method. The lock is still owned by Thread-1.
Thread.sleep(1000);
}
System.out.println( Thread.currentThread().getName() + " : after wait/notify");
} catch (InterruptedException ex) {
Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void doSomeWorkThatRequiresALockLikeRemoveOrAdd()
{
// Do some work that requires a lock like remove or add
}
}
we have two threads accessing one list via a synchronized method. Can we
a) rely on the run time to make sure that each of them will receive access to the method based on the order they tried to or
b) does the VM follow any other rules
c) is there a better way to serialize the requests?
No, synchronized will give access in any order (Depends on the JVM implementation). This could even cause Threads to starve in some scenarios.
You can ensure the order by using ReentrantLock (since Java 5.0) with the fair=true option. (Lock lock = new ReentrantLock(true);)
No you cannot be sure that two calls to a synchronized method will occur in order. The order is unspecified and implementation dependent.
This is defined in the 17.1 Locks section of the JLS. Notice that is says nothing about the order in which threads waiting on a lock should gain access.
You can't rely on the order in which the particular method is called from each threads. If it is only two threads may be yes. But imagine if there are 3 threads and 1 thread already acquired access. The other 2 threads when they try to access will wait and any one of them can be awarded the access, and this does not depend on the order in which they called this method.
So, it is not suggested to rely on the order.
c) is there a better way to serialize the requests?
Are you by any chance using the list as a queue, i.e., does the usage pattern look something like this?
while (some condition) {
synchronized(theList){
anItem = get and remove an element from theList
}
do some work with anItem
}
If so, you may want to look at the BlockingQueue interface instead of using your own locking schemes. The implementations (like ArrayBlockingQueue) have settings for fairness and more.
I always leave syncs to app server or engine unless defining own intensity
I have solved similar problem with couple of instrument. The problem I was trying to solve is Ping Pong Service. two thread one prints Ping and the other prints Pong. but They have to be SEQUENTIAL. (no double Ping or double Pong)
I will put one of the Implementation here but you can have a look other implementation (6 or 7 different way for now)
https://github.com/tugrulkarakaya/pingpong
import java.util.concurrent.*;
public class Method2CyclicBarrier {
ExecutorService service;
CyclicBarrier c1 = new CyclicBarrier(2);
CyclicBarrier c2 = new CyclicBarrier(2);
public static void main(String[] args) {
Method2CyclicBarrier m = new Method2CyclicBarrier();
m.runPingPong();
}
public void runPingPong(){
service = Executors.newFixedThreadPool(2);
service.submit(() -> this.printPing(c1, c2));
service.submit(() -> this.printPong(c1, c2));
}
public void printPing(CyclicBarrier c1, CyclicBarrier c2) {
while(!Thread.currentThread().isInterrupted()) {
try {
c1.await();
System.out.println("PING");
c2.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
catch(BrokenBarrierException ex){
}
}
}
public void printPong(CyclicBarrier c1, CyclicBarrier c2){
while(!Thread.currentThread().isInterrupted()) {
try {
c1.await();
c2.await();
System.out.println("PONG");
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch(BrokenBarrierException ex){
}
}
}
}
Yes.
If access to the list is via one synchronized method, concurrent requests from multiple threads will be serialized.