Suppose we have a class:
public class Foo {
public void first() { print("first"); }
public void second() { print("second"); }
public void third() { print("third"); }
}
The same instance of Foo will be passed to three different threads. Thread A will call first(), thread B will call second(), and thread C will call third(). Design a mechanism and modify the program to ensure that second() is executed after first(), and third() is executed after second().
Note:
We do not know how the threads will be scheduled in the operating system, even though the numbers in the input seem to imply the ordering. The input format you see is mainly to ensure our tests' comprehensiveness.
Example 1:
Input: nums = [1,2,3] Output: "firstsecondthird" Explanation: There are three threads being fired asynchronously. The input [1,2,3] means thread A calls first(), thread B calls second(), and thread C calls third(). "firstsecondthird" is the correct output.
Example 2:
Input: nums = [1,3,2] Output: "firstsecondthird" Explanation: The input [1,3,2] means thread A calls first(), thread B calls third(), and thread C calls second(). "firstsecondthird" is the correct output.
Constraints:
nums is a permutation of [1, 2, 3].This approach employs semaphores to control the execution order of methods. Since semaphores are synchronization constructs that can be used to control access to a common resource in a concurrent system, we can use them to gate the execution of 'second' and 'third' methods until 'first' and 'second' have completed, respectively. The semaphore for 'second' starts at 0 and is incremented by 'first', allowing 'second' to run. Similarly, 'third' can proceed only after 'second' increments its semaphore.
In Python, we utilize the Semaphore class from the threading module. We initiate two semaphores, each initialized to 0. The first method prints 'first' and then releases the semaphore for second. The second method waits (acquires) on the semaphore before printing 'second' and then releases the semaphore for third. The third method waits (acquires) on its semaphore before printing 'third'.
Java
C#
Time Complexity: O(1) for each method call. Space Complexity: O(1).
This approach leverages locks and condition variables to achieve the desired execution order. By associating each method with a condition variable, the appropriate method waits (and releases lock) until the previous condition is signaled, facilitating the required sequence.
In Python, we use a lock with condition variables to ensure proper sequencing. The first method sets a flag and notifies other methods once it completes. Second waits until the first_done is True and proceeds similarly for third, which waits for second_done.
JavaScript
Time Complexity: O(1) for each method call. Space Complexity: O(1).
| Approach | Complexity |
|---|---|
| Using Semaphores | Time Complexity: O(1) for each method call. Space Complexity: O(1). |
| Using Locks and Conditions | Time Complexity: O(1) for each method call. Space Complexity: O(1). |
My Brain after 569 Leetcode Problems • NeetCode • 2,927,632 views views
Watch 9 more video solutions →Practice Print in Order with our built-in code editor and test cases.
Practice on FleetCodePractice this problem
Open in Editor