Interaction between threads. Methods wait(), notify(), notifyAll(). Examples
Before studying this topic, it is recommended that you familiarize yourself with the following topic:
Search other resources:
Contents
- 1. Means of interaction between threads. Methods wait(), notify(), notifyAll()
- 2. Scheme (figure) of the interaction between two parallel threads
- 3. Implementation of a polling system between threads. An example of exchanging values between two threads that run in parallel
- 4. An example of sequential synchronized use of a shared array of numbers between threads. Implementation of the polling system
- Related topics
1. Means of interaction between threads. Methods wait(), notify(), notifyAll()
To provide interaction between threads of execution in the Object class, 3 methods are implemented.
1. Method wait() – puts the calling thread into a wait state. In this case, the calling thread releases the monitor that has access to the resource. The wait continues until another thread of execution that has entered the monitor calls the notify() method.
According to the Java documentation, the general most common implementation of the method is as follows:
public final void wait() throws java.lang.InterruptedException;
In Java, the wait() method has other overloaded implementations that allow you to wait for a specified period of time.
2. The notify() method – resumes execution of the thread from which the wait() method was called for the same object.
According to the Java documentation, the general form of the method is as follows:
public final native void notify();
3. The notifyAll() method – resumes execution of all threads from which the wait() method was called on the same object. Control is transferred to one of these streams.
The general form of the method is as follows:
public final native void notifyAll();
⇑
2. Scheme (figure) of the interaction between two parallel threads
The figure shows the interaction between two threads that run in parallel. Threads exchange an instance of the Value class, which stores some value. Each thread is represented by a class. The class that forms the Value instance is called PutValue. The class that reads the Value instance is called GetValue.
First, some value of the Value instance is formed (written) by the PutValue stream. At this point, the GetValue thread waits for a message from the PutValue thread using a circular call to the wait() method. After the Value class is instantiated, the PutValue thread calls the notify() method. As a result, control is transferred to the GetValue thread, which must read the value. Now the PutValue thread is waiting (the wait() method). Once the GetValue stream finishes reading, it signals this by calling the notify() method.
The process of synchronized communication between threads can be repeated as many times as necessary.
Figure 1. Interaction between parallel threads PutValue and GetValue, that share a common resource Value
⇑
3. Implementation of a polling system between threads. An example of exchanging values between two threads that run in parallel
Task. Implement value exchange between two threads that run in parallel. The first thread generates some random number. The second thread waits until the number is generated by the first thread. Then this number is passed to the second thread and displayed there. After that, control is again transferred to the first thread to generate the next random number. The process is repeated a specified number of times.
Solution. To solve this problem, you need to form 3 classes:
- the Number class, which defines the number used to exchange between threads;
- FormNumber class – represents a stream that generates random numbers that will be passed to the GetNumber stream;
- GetNumber class – represents a thread that receives numbers from the FormNumber thread.
// A class that implements methods that synchronously receive and return a number class Number { int n; // a flag that determines whether the thread is parallel // formed/received a number boolean valueSet = false; // Method that returns a number synchronized int get() { while (!valueSet) { try { wait(); } catch (InterruptedException e) { System.out.println(e.getMessage()); } } valueSet=false; notify(); return n; } // Method used to pass a number to another thread synchronized void put(int n) { // Wait until received (valueSet = false) while(valueSet) { try { wait(); } catch(InterruptedException e) { System.out.println(e.getMessage()); } } this.n = n; valueSet=true; notify(); } } // A class representing a thread that forms a number class FormNumber implements Runnable { Number num; // number which is formed int count; // the number of numbers to send to another thread Thread thread; // reference to the current thread // Constructor - gets the number and count of generated numbers FormNumber(Number num, int count) { // Fill in internal variables this.num = num; this.count = count; // Create a thread and start it for execution thread = new Thread(this, "FormNumber"); thread.start(); } // Method that implements thread execution code public void run() { for (int i=0; i<count; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } // Generate some random number from 1 to 100 int number = (int)(Math.random()*100+1); System.out.println("Thread: " + thread.getName() + ", number formed: " + number); num.put(number); } } } class GetNumber implements Runnable { // Internal variables Number num; // number which is formed int count; // the amount of numbers you want to get Thread thread; // reference to the current thread GetNumber(Number num, int count) { // Fill in internal variables this.num = num; this.count = count; // Create a thread and start it for execution thread = new Thread(this, "GetNumber"); thread.start(); } // The method that contains the thread execution code public void run() { for (int i=0; i<count; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread: " + thread.getName() + ", received number " + num.get()); } } } public class Threads { public static void main(String[] args) { // Thread test Number num = new Number(); new FormNumber(num, 5); // Pass 5 numbers to another thread new GetNumber(num, 5); // Get 5 numbers from another thread } }
The result of the program
Thread: FormNumber, number formed: 26 Thread: GetNumber, received number 26 Thread: FormNumber, number formed: 10 Thread: GetNumber, received number 10 Thread: FormNumber, number formed: 88 Thread: GetNumber, received number 88 Thread: FormNumber, number formed: 58 Thread: GetNumber, received number 58 Thread: FormNumber, number formed: 70 Thread: GetNumber, received number 70
⇑
4. An example of sequential synchronized use of a shared array of numbers between threads. Implementation of the polling system
The solution of this example can be used as a template for implementing the interaction between the threads themselves.
Task. Implement access to the array alternately from two threads. The first stream forms an array of numbers of the specified length. The second thread reads this array of numbers. The second thread waits for the first thread to form an array of numbers. Likewise, the first thread must wait until the second thread has finished reading the array.
Demonstrate the interaction of threads of execution a specified number of times.
Solution. To solve the task, you need to implement 3 classes:
- Array – defines an array of integers of a given size;
- FormArray – is designed to form an array of random numbers of arbitrary size;
- GetArray – used to get an array of numbers previously generated in the FormArray class.
The Array class implements the following class members:
- AI – an array of integers. This array is a shared resource for threads that the FormArray and GetArray classes correspond to;
- formArray – a boolean flag that is used to determine the timeout period for threads;
- constructor Array(), which takes as a parameter the size of the array. The constructor allocates memory for the AI array;
- the get() method – used by the GetArray stream to read the AI array;
- the set() method – used by the FormArray thread to form an array of integers;
- the getArray() method is a reference to the private AI array.
Both classes FormArray and GetArray implement the Runnable interface. Classes encapsulate threads of execution. The following constituent elements are implemented in the classes:
- A – an instance (object) of the Array class. This instance stores an array of integers;
- count is an integer value that determines the number of iterations each of which will generate a new array;
- constructor;
- the run() method containing the code for the thread. For the FormArray class, this method contains the code to generate an array of integers by calling the put() method of instance A. In the run() method of the GetArray class, the get() method of instance A is called to read the array generated in the parallel FormArray stream.
// A class that implements an array with synchronized get(), set() methods. class Array { // Hidden internal class fields private int[] AI; private boolean formArray; // Constructor - gets the size of the array from outside Array(int size) { // Form the array AI = new int[size]; formArray = false; } // Method for synchronized array reading synchronized int[] get() { // wait until the array is formed while (!formArray) { try { wait(); } catch (InterruptedException e) { System.out.println(e.getMessage()); } } // Change interaction flag formArray = false; // Tell another thread that an array has been received notify(); // Return the result return AI; } // Method of synchronized writing of an array of numbers synchronized void put(int[] _AI) { // Wait until array is read (formArray = false) while(formArray) { try { wait(); } catch(InterruptedException e) { System.out.println(e.getMessage()); } } // Write array to shared resource AI = _AI; // Change flag interaction between threads formArray = true; // Tell another thread that the array is formed notify(); } // A method to access the array AI int[] getArray() { return AI; } } // A class that implements a thread that generates an array of random numbers class FormArray implements Runnable { // Internal class fields private Array A; // the array itself private int count; // number of iterations of array formation // Constructor. // Parameters: // - A - reference to the shared array; // - count - the number of iterations forming the array FormArray(Array A, int count) { // Fill in internal variables this.A = A; this.count = count; // Create a thread new Thread(this, "FormArray").start(); } // Execution of thread public void run() { // count - the number of iterations forming the array for (int k = 0; k<count; k++) { try { // Delay 1 second Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // generate a random array with random numbers int[] AI = new int[A.getArray().length]; // write random numbers to the array for (int i=0; i<AI.length; i++) AI[i] = (int)(Math.random()*AI.length+1); // Output the formed array System.out.println("Сформовано: "); for (int i=0; i<AI.length; i++) System.out.print(AI[i] + " "); System.out.println(); // write an array into a common synchronized resource A.put(AI); } } } // The class implements a thread which is read in an array of integers. // The array of integers preformed in the instance of FormArray class class GetArray implements Runnable { // Internal data members of a class private Array A; private int count; // Constructor. Receives 2 parameters: // - _A - an array, which is a common resource for two threads; // - count - the number of iterations (steps) of reading the array from the parallel thread. GetArray(Array _A, int count) { // Fill in internal variables A = _A; this.count = count; new Thread(this, "GetArray").start(); } // Thread execution code public void run() { for (int k=0; k<count; k++) { try { // Delay 0.2 seconds Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } // Get an array of numbers from a synchronized thread int[] AI = A.get(); // Print the resulting array System.out.println("Отримано: "); for (int i=0; i<AI.length; i++) System.out.print(AI[i] + " "); System.out.println(); } } } public class Threads { public static void main(String[] args) { Array A = new Array(10); new FormArray(A, 6); new GetArray(A, 6); } }
⇑
Related topics
- Multitasking. Threads of execution. Basic concepts
- Java language tools for working with threads of execution. Thread class. Runnable interface. Main thread of execution. Creating a child thread
- Methods of the Thread class: getName(), start(), run(), sleep(). Examples
- Methods of the Thread class: join(), isAlive(), getPriority(), setPriority(). Examples
- Synchronization. Monitor. General concepts. The synchronized keyword
- The state of the thread of execution. The getState() method. Example
⇑