简体   繁体   中英

Java Concurrency based on condition

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??

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.

eg 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.

eg

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM