Reputation: 10231
Create a method which accept a integer as a argument and print on console. This method is accessed by multiple threads. If two or more threads call the method with same value then only one thread should allow to print the value other threads should wait. If values are different then all threads should allow to print the value. I know interning would help here but Java interning happens till values less than 128. After that two Integer having same value are different object... Can it be done? Any provision for synchronizing on condition??
Upvotes: 1
Views: 863
Reputation: 305
private static final Set<Integer> lockedIntegers = new HashSet<>();
private void lock(Integer key) throws InterruptedException {
synchronized (lockedIntegers) {
while (!lockedIntegers.add(key)) {
lockedIntegers.wait();
}
}
}
private void unlock(Integer key) {
synchronized (lockedIntegers) {
lockedIntegers.remove(key);
lockedIntegers.notifyAll();
}
}
public void printEqualIntegersSynchronously(Integer key) throws InterruptedException {
try {
lock(key);
System.out.println(key);
//Do whatever you need with your key.
//For different keys this part is executed in parallel.
//For equal keys this part is executed synchronously.
} finally {
unlock(key);
}
}
try-finally - is very important - you must guarantee to unlock waiting threads after your operation even if your operation threw exception. 'System.out.println' most probably will never throw exception - but for other real situations 'try-finally' is mandatory. And by the way 'System.out.println' is already synchronized by itself, so exactly for 'System.out.println' it is not needed.
Upvotes: 0
Reputation: 533432
the requirement about preventing multiple threads from printing the same value, but allowing them print differing ones
The simplest way to prevent this is to have a set of Integers printed already. Since you are printing the overhead of using a lock is trivial.
Set<Integer> printed = Collections.synchronizedSet(new HashSet<Integer>());
// when printing
if (printed.add(num)) // will one be true the first time for each number
System.out.println("num: " + num);
Can it be done?
Printing to the console is synchronized already and no matter what you do, all thread will synchorize their printing no matter what you do. Adding more locking won't change that.
e.g. from PrintStream which implements System.out and err
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
You cannot simply decide to ignore the the synchronized
here from the caller.
Any provision for synchronizing on condition??
The simplest thing to do is to lock on a different lock or a thread local. Locking an uncontented object is very quick.
e.g.
synchronized(shared ? sharedObject : Thread.currentThread()) {
}
BTW This is very strange/confusing thing to do. I would seriously consider changing your design so this is not required. Writing normal multi-threaded code is hard enough to write/understand.
Upvotes: 1