Thursday, June 12, 2025
HomeJavaQuiz your self: Locking mechanisms and Java’s postincrement ++ operator

Quiz your self: Locking mechanisms and Java’s postincrement ++ operator


Oracle Java Certification, Oracle Java Prep, Oracle Java Guides, Java Career, Java Jobs, Java Skills, Java Preparation


Let’s see if this quiz code will work persistently.

Think about that your colleagues wish to carry out calculations in parallel. In pursuit of thread security, they applied the next locking mechanism:

var lock = new ReentrantLock();

var s = IntStream.of(1, 2, 3);

var i = s.parallel().map(

  v -> {

    lock.tryLock();

    var res = v++;

    lock.unlock();

    return res;

  }

).sum();

System.out.println(i);

Which assertion is appropriate about this code? Select one.

A. It persistently prints 12 to console.

B. It would print 12 to console.

C. It persistently throws an exception.

D. It would throw an exception.

E. It prints nothing, hanging indefinitely.

Reply. This query facilities on the habits of the ReentrantLock.tryLock() methodology, and it expects you to grasp how the postincrement ++ operator works.

Contemplate the computation carried out by the block lambda within the map step of the stream. It takes its argument, v, copies that worth to the native variable res, after which returns the worth of res. Discover that the increment operator used on v is a postincrement operator. Because of this, the numbers which are within the stream on the level of the sum() operation are 1, 2, and three. Due to this fact, if any worth is printed, it may solely be 6. This tells you that choices A and B, each of which recommend a attainable output of 12, have to be incorrect.

Now contemplate the locking habits. The tryLock methodology by no means blocks—if the lock can’t be obtained, the strategy instantly returns false, and execution proceeds with no lock held. Then again, if the lock is obtained efficiently, the strategy returns true and, as earlier than, continues with out blocking.

As a result of tryLock by no means blocks, you’ll be able to decide that possibility E have to be incorrect; there’s no purpose for the code to hold indefinitely.

Now you get to the crux of the query. If an unlock name is made on a ReentrantLock that isn’t within the locked state, it throws an IllegalMonitorStateException. You need to determine whether or not this may undoubtedly occur or is just a risk.

Wanting on the code, it’s simple to think about that because the three numbers arrive on the map methodology, they may accomplish that with a timing that merely leads to three nonoverlapping units of calls: tryLock, unlock; tryLock, unlock; and tryLock, unlock. If that sequence occurs, no exception will come up.

Which means that the exception would possibly come up however will not be assured. From this you already know that possibility D is appropriate as a result of the code would possibly throw an exception. You additionally know that possibility C is inaccurate as a result of there’s no assure the exception can be thrown persistently.

By the way in which, the code can undoubtedly be fastened.

Basically, there isn’t any want for locking on this code as a result of the map operation’s lambda does nothing to the info within the stream, and the map operation can merely be deleted. If this code have been a placeholder or an error—maybe the intention was to double the values (anticipating the reply 12)—all that’s wanted is the next easy step in place of the present map operation:

.map(v -> 2 * v)

This code wants no lock as a result of it interacts solely with method-local knowledge and never with something shared; thus, there’s no thread-safety subject.

If, nonetheless, the intention was truly to mutate some shared knowledge (there’s no indication of that impact on this code), locking is perhaps an appropriate answer (although such unintended effects are strongly discouraged in stream code anyway). If that have been meant, tryLock can be unsuitable for 2 causes: The operation can be unprotected if no lock have been obtained, and maybe the operation would merely be ignored if the failure to lock precipitated the code to skip the operation.

The next modification to the present code would keep away from the exception, however it might not truly assure a lock and would skip the operation if no lock have been obtained:

.map(

  v -> {

    var res = v;

    if (lock.tryLock()) {

      v++; // nonetheless ineffective and skipped if no lock obtained!

      lock.unlock(); // solely unlock if lock succeeded

    }

    return res;

  }

)

To really defend an operation with mutual exclusion, the code may seem like the next:

.map(

  v -> {

    var res = v;

    lock.lock() // blocking name, waits for locking to succeed

    attempt {

      v++; // nonetheless ineffective, however protected by a lock 

    } lastly {

      lock.unlock(); // unlock reliably

    }

    return res;

  }

}

Discover the really useful location for an unlock() operation is in a lastly block, which ensures that regardless of how the physique of the attempt block proceeds or terminates, the lock will certainly be launched.

Conclusion. The proper reply is possibility D.

Supply: oracle.com

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments