The communication between Java multithreading

Source: Internet
Author: User

In the previous section, we introduced the importance of using synchronization mechanisms in multithreaded programming and learned how to implement synchronous methods to properly access shared resources. The relationships between these threads are equal, and there is no dependency between them, competing for CPU resources, and unconditionally preventing other threads from accessing the shared resource asynchronously. However, there are a lot of real-world problems that require not only simultaneous access to the same shared resources, but also threads that are pinned to each other and pushed forward by communicating with each other. So how do you communicate between multiple threads?



Solution Ideas

In real-world applications, it is often necessary to have multiple threads access shared resources in a certain order, such as classic producer and consumer issues. Such questions describe a situation in which a product can be stored in a warehouse, where the producer puts the product in the warehouse and the consumer takes the product out of the warehouse. If there is no product in the warehouse, the producer can put the product into the warehouse, otherwise stop production and wait until the product in the warehouse is taken away by the consumer. If a product is placed in the warehouse, the consumer can take the product away from consumption, otherwise stop spending and wait until the product is placed in the warehouse again. Obviously, this is a synchronization problem, where producers and consumers share the same resources, and the producers and consumers depend on each other and move forward in terms of each other. But how do you write a program to solve this problem?

The traditional way of thinking is to use the method of cyclic detection, which determines the order of thread advancement by repeatedly checking whether a particular condition is established. For example, once producer production is finished, it will continue to use cyclic testing to determine whether the products in the warehouse are consumed by consumers, and consumers will immediately use the loop detection method to determine whether the product is placed in the warehouse after the end of consumption. Obviously, these operations are CPU-intensive and are not worth advocating. So is there a better way to solve this kind of problem?

First, only the Synchronized keyword is sufficient when the thread needs to wait for a condition before it can continue execution. Because although the Synchronized keyword can prevent concurrent updates to the same shared resource, it enables synchronization, but it cannot be used to implement message passing between threads, known as communication. In dealing with such problems, a principle must be followed, that is, for producers, before producers do not produce, to inform consumers to wait, after the production of producers, immediately notify consumer consumption, for consumers, after consumer consumption, to inform the producer has finished consumption, The need to continue to produce new products for consumption.

In fact, Java provides 3 very important ways to skillfully solve communication problems between threads. These 3 methods are: Wait (), notify (), and Notifyall (). They are all the final methods of the object class, so each class has them by default.

Although all classes have these 3 methods by default, they are only meaningful if the Synchronized keyword is scoped to the same synchronization problem and is used in conjunction with the 3 methods.

The syntax format that these methods declare in the object class is as follows:

final void Wait () throws Interruptedexception

Final void Notify ()

final void Notifyall ()

The call to Wait () method allows the thread that invokes the method to release the lock on the shared resource, and then exits from the run state and into the wait queue until it is awakened again. The call to the Notify () method wakes the first thread waiting in the queue to wait for the same shared resource, and causes the thread to exit the wait queue and enter the operational state. The call to the Notifyall () method allows all threads waiting in the queue to wait for the same shared resource to exit from the waiting state and into the operational state, at which point the highest priority thread executes first. Obviously, using these methods eliminates the need to cycle through the state of shared resources, but instead wakes up the threads in the waiting queue directly when needed. This not only saves valuable CPU resources, but also improves the efficiency of the program.

Because the wait () method is declared to throw a Interruptedexception exception when it is declared, it needs to be placed in the Try...catch code block when the Wait () method is called. In addition, the method needs to be placed in a synchronization code snippet, otherwise the following exception will occur:

"Java.lang.IllegalMonitorStateException:current Thread not owner"

Is it possible for these methods to communicate between threads? The following is a multi-threaded synchronization model: Producer and consumer issues to illustrate how to solve the problem of communication between multiple threads through a program.

Specific steps

The following program demonstrates the specific implementation of communication between multiple threads. The program uses 4 classes, where the Sharedata class is used to define shared data and synchronization methods. The wait () method and the Notify () method are called in the synchronization method, and a semaphore is used to implement message passing between threads.

Example 4.6.1 Communicationdemo.java Description: Message passing process between producer and consumer

Class Sharedata

{

private char C;

Private Boolean isproduced = false; Signal Volume

Public synchronized void Putsharechar (char c)//synchronous Method Putsharechar ()

{

if (isproduced)//If the product is not consumed, the producer waits for

{

Try

{

Wait (); Producers wait

}catch (Interruptedexception e) {

E.printstacktrace ();

}

}

THIS.C = C;

isproduced = true; Mark has been produced

Notify (); Inform consumers that they have been produced and can consume

}

Public synchronized char Getsharechar ()//synchronous Method Getsharechar ()

{

if (!isproduced)//If the product is not yet manufactured, the consumer waits for

{

Try

{

Wait (); Consumer Waiting

}catch (Interruptedexception e) {

E.printstacktrace ();

}

}

isproduced = false; Mark has been consumed

Notify (); Notification requires production

return THIS.C;

}

}

Class Producer extends thread//producer Threads

{

Private Sharedata S;

Producer (Sharedata s)

{

THIS.S = s;

}

public void Run ()

{

for (char ch = ' A '; Ch <= ' D '; ch++)

{

Try

{

Thread.Sleep ((int) (Math.random () *3000));

}catch (Interruptedexception e) {

E.printstacktrace ();

}

S.putsharechar (CH); Put the product into the warehouse

SYSTEM.OUT.PRINTLN (ch + "is produced by Producer.");

}

}

}

Class Consumer extends thread//consumer threads

{

Private Sharedata S;

Consumer (Sharedata s)

{

THIS.S = s;

}

public void Run ()

{

Char ch;

do{

Try

{

Thread.Sleep ((int) (Math.random () *3000));

}catch (Interruptedexception e) {

E.printstacktrace ();

}

ch = S.getsharechar (); Remove the product from the warehouse

SYSTEM.OUT.PRINTLN (ch + "is consumed by Consumer.");

}while (ch! = ' D ');

}

}

Class Communicationdemo

{

public static void Main (string[] args)

{

Sharedata s = new Sharedata ();

New Consumer (s). Start ();

New Producer (s). Start ();

}

}

The above program shows that the producer produces a, B, C, D four characters, consumer consumption of the four characters of the entire process, the program results 4.6.1 shows:

Figure 4.6.1 Examples of producers and consumers

As you can see from the running results of the program, although the consumer thread was first started in the main method, the consumer thread calls the Wait () method to wait until the producer thread produces the product and puts it into the warehouse because there are no products in the warehouse. Then use the Notify () method to wake it.

Because a certain amount of sleep time is specified in two threads, it is also possible that the producer produces the product into the warehouse and notifies the consumer thread in the waiting queue, however, since the sleep time is too long and the consumer thread has not intended to consume the product, at this point, Producer thread to produce the next product, the result is that the product in the warehouse is not consumed, so the producer thread executes the Wait () method into the waiting queue until the consumer thread consumes the product in the warehouse and passes the Notify () method to wake up the producer thread in the wait queue. It can be seen that the two threads must be synchronized in addition to each other in order to continue to move forward through communication.

In front of this program, producers can only produce one product at a time, and consumers can only consume one product at a time. So in reality, there are situations where producers can produce multiple products at once, so long as the warehouse capacity is large enough, it can be produced all the time. Consumers can also consume multiple products at once until there are no products in the warehouse.

However, whether you are producing a product to a warehouse or consuming it from a warehouse, you can only allow one operation per time. Obviously, this is also a synchronization problem, but in this problem the shared resource is a resource pool that can hold multiple resources. The following is an example of a stack structure that shows how to solve the problem of thread communication in the program code.

Example 4.6.2 Communicationdemo2.java

Class Syncstack//Synchronization stack class, you can put more than one data at a time

{

private int index = 0; Stack pointer initial value is 0

Private char[] buffer = new CHAR[5]; Stack has 5 characters of space

Public synchronized void push (char c)//In-Stack synchronization method

{

if (index = = buffer.length)//Stack is full, cannot be entered into the stack

{

Try

{

This.wait (); Waiting for the stack thread to stack up the data

}catch (Interruptedexception e) {}

}

Buffer[index] = c; Data into the stack

index++; Pointer plus 1, space in stack is reduced

This.notify (); Notifies other threads to stack data

}

Public synchronized char pop ()//out of stack synchronization method

{

if (index = = 0)//stack no data, cannot out stack

{

Try

{

This.wait (); Waiting for the stack thread to put the data into the stack

}catch (Interruptedexception e) {}

}

This.notify (); Notify other threads to the stack

index--; Move the pointer down

return Buffer[index]; Data out Stack

}

}

Class Producer implements Runnable//producer class

{

Syncstack s; The letters generated by the producer class are saved to the synchronization stack

Public Producer (Syncstack s)

{

THIS.S = s;

}

public void Run ()

{

Char ch;

for (int i=0; i<5; i++)

{

Try

{

Thread.Sleep ((int) (Math.random () *1000));

}catch (Interruptedexception e) {}

ch = (char) (Math.random () *26+ ' A '); Randomly generates 5 characters

S.push (CH); Put characters into the stack

System.out.println ("Push" +ch+ "in Stack"); Print characters into the stack

}

}

}

Class Consumer implements Runnable//consumer

{

Syncstack s; The characters acquired by the consumer class come from the synchronization stack

Public Consumer (Syncstack s)

{

THIS.S = s;

}

public void Run ()

{

Char ch;

for (int i=0;i<5;i++)

{

Try

{

Thread.Sleep ((int) (Math.random () *3000));

}catch (Interruptedexception e) {}

ch = s.pop (); Reading characters from the stack

System.out.println ("Pop" +ch+ "from Stack"); Print characters out of stack

}

}

}

public class CommunicationDemo2

{

public static void Main (string[] args)

{

Syncstack stack = new Syncstack ();

The following consumer class objects and producer class objects operate on the same synchronization stack object

thread T1 = new Thread (new Producer (stack)); Thread instantiation

Thread t2 = new Thread (new Consumer (stack)); Thread instantiation

T2.start (); Thread Start

T1.start (); Thread Start

}

}

The program introduces a stack array buffer[] to emulate the resource pool and enable both the producer and consumer classes to implement the Runnable interface, then create two threads that share the same stack resource in the main program, and intentionally start the consumer thread before starting the producer thread. Please take a closer look at the similarities and differences between the example 4.6.1 and this example while reading the program, and experience the author's intentions. The program results output 4.6.2 shows:

Figure 4.6.2 Producer and consumer issues for shared resource pools

Because it is a stack structure, it conforms to the LIFO principle. Interested readers can also be used in accordance with the FIFO principle of the queue structure to simulate the process of inter-thread communication, I believe that can be accessed through the relevant information to solve the problem, here is no longer give the program code, as a study questions for the reader to practice.

Expert notes

This section describes three important methods: Wait (), notify (), and Notifyall (). Using them can efficiently accomplish communication problems between multiple threads, so that there is no need to use cyclic detection to wait for a condition to occur on a communication issue, because this method is extremely wasteful of CPU resources, and of course this is not expected. In the example 4.6.1, in order to communicate better, a semaphore is introduced to transmit information. The use of semaphores to determine whether a thread waits is undoubtedly a very safe operation and is worth advocating. In addition, a resource pool is introduced as a shared resource in example 4.6.2, and the communication problem of how to implement multithreading in this case is solved. It is hoped that readers will be able to extrapolate and write procedures for solving more complex problems.

Expert advice

It is certain that the use of the Wait (), notify (), and Notifyall () methods is indeed a good solution to the problem of inter-threading communication. However, it should also be understood that these methods are artifacts of more complex locking, queueing, and concurrency code. In particular, it is risky to use Notify () instead of Notifyall (). Unless you know exactly what each thread is doing, it is best to use Notifyall (). In fact, a new package has been introduced in JDK1.5: the Java.util.concurrent package, a widely used open source toolkit, is a useful concurrency utility. It is entirely possible to replace the wait () and notify () methods to write your own scheduler and locks. The relevant information can be consulted, the book will not be described in detail.

Related issues

Java provides a variety of input and output streams, which enable programmers to easily manipulate data. Where pipe flow is a special flow that transmits data directly between different threads. One thread sends the data to the output pipeline, and the other thread reads the data from the input pipeline. By using pipelines, you achieve the purpose of communicating between multiple threads. So, how do you create and use pipelines?

Java provides two special classes specifically designed to handle pipelines, which are the PipedInputStream class and the PipedOutputStream class.

Where PipedInputStream represents the output of the data in the pipeline, that is, the thread reads one end of the data from the pipe, and PipedOutputStream represents the input of the data in the pipeline, which is the end of the thread writing to the pipe, These two classes can be used together to create a pipe flow object for data input and output.

Once the pipeline is created, it is possible to use multi-threaded communication mechanism to read and write the data through the pipeline, so that multi-threaded programming plays a more important role in practical application.

Http://www.cnblogs.com/newthing/archive/2008/01/30/2157786.html

The communication between Java multithreading

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.