Deep parsing of Java thread synchronization and inter-thread communication _java

Source: Internet
Author: User
Tags mutex semaphore

Java thread Synchronization
When two or more threads need to share resources, they need some way to determine that a resource is only occupied by one thread at a time. The process to achieve this is called Synchronization (synchronization). As you can see, Java provides unique, language-level support for this.

The key to synchronization is the concept of enhancement (also called Semaphore semaphore). A enhancement is a mutex, or a mutex, that is a mutually exclusive locked object. At a given time, only one thread can get a pipe. When a thread needs to be locked, it must go into the pipe. All other threads that attempt to enter the locked enhancement must suspend until the first thread exits the pipe. These other threads are called wait pipes. A thread that has a pipe can enter the same enhancement again if it wishes.

If you use synchronization in other languages, such as C or + +, you'll know it's a bit weird to use. This is because many languages themselves do not support synchronization. Instead, for synchronization threads, the program must use the operating system source language. Fortunately, Java is synchronized with language elements, and most of the synchronization-related complexities are eliminated.

You can synchronize your code in two ways. Both of these include the use of the Synchronized keyword, which is explained in the following two ways.
Using the synchronization method

Synchronization in Java is simple, because all objects have their corresponding implicit pipe path. The process of entering an object is to invoke a method modified by the Synchronized keyword. When a thread is inside a synchronization method, all other threads that attempt to invoke the same instance of the method (or other synchronization method) must wait. In order to exit the pipe and discard control of the object to other waiting threads, the thread that owns the pipe only needs to return from the synchronization method.

To understand the need for synchronization, let's start with a simple example where synchronization is not used. The following program has three simple classes. The first is CallMe, which has a simple method of call (). The call () method has a string parameter named Msg. This method attempts to print the MSG string within square brackets. The interesting thing is to call Thread.Sleep (1000) after calling call () to print the opening parenthesis and the MSG string, which pauses the current thread for 1 seconds.

The constructor for the next class, caller, references an instance of the CallMe and a string, which exist in Target and MSG, respectively. The constructor also creates a new thread that invokes the run () method of the object. The thread starts immediately. The run () method of the caller class invokes the call () method of the CallMe instance target through the parameter msg string. Finally, the Synch class starts with three instances of a simple instance of creating CallMe and caller with different message strings.

The same instance of CallMe is passed to each caller instance.

 "" ""//"" not synchronized. Class Callme {void call (String msg) {System
    . Out.print ("[" + msg);
    try {thread.sleep (1000);
    catch (Interruptedexception e) {System.out.println ("interrupted");
  } System.out.println ("]");
  Class Caller implements Runnable {String msg;
  Callme Target;
  Thread T;
    Public Caller (Callme Targ, String s) {target = Targ;
    msg = s;
    t = new Thread (this);
  T.start ();
  public void Run () {Target.call (msg);
    } class Synch {public static void main (String args[]) {Callme target = new Callme ();
    Caller ob1 = new Caller (target, "Hello");
    Caller ob2 = new Caller (target, "Synchronized");
    Caller ob3 = new Caller (Target, "world");
     Wait for threads to end try {ob1.t.join ();
     Ob2.t.join ();
    Ob3.t.join ();
    catch (Interruptedexception e) {System.out.println ("interrupted"); }
  }
}

The output of the program is as follows:

Hello[synchronized[world]
]
]

In this case, by calling Sleep (), the call () method allows execution to be converted to another thread. The result is a mixed output of three message strings. There are no methods in the program that prevent three threads from calling the same object at the same time. This is a competition because three threads are scrambling to complete the method. The example uses sleep () to make the effect repetitive and obvious. In most cases, competition is more complex and unpredictable because you cannot be sure when context conversions occur. This causes the program to run correctly and sometimes with errors.

In order to achieve the desired purpose of the above example, you must have the right to use call () continuously. That is, at some point, you have to limit only one thread to dominate it. To do this, you only need to add the keyword synchronized before the call () definition, as follows:

Class Callme {
  synchronized void call (String msg) {
    ...

This prevents other threads from entering call () when one thread uses call (). After synchronized is added to call (), the program output is as follows:

[Hello]
[Synchronized]
[World]

At any time in a multithreaded situation, you have a method or multiple methods to manipulate the internal state of the object, you must use the Synchronized keyword to prevent state competition. Remember, once a thread enters the synchronization method of an instance, no other thread can enter the synchronization method for the same instance. However, other unsynchronized methods of the instance can still be invoked.
Synchronization statements

Although creating a synchronization method inside a class that you create is a simple and effective way to achieve synchronization, it is not effective at all times. The reason for this, please follow the thinking. Suppose you want to get synchronous access to a class object that is not designed for multithreaded access, that is, the class does not use the Synchronized method. Also, the class is not your own, but it is created by a third party and you cannot get its source code. In this way, you can't add a synchronized modifier before the related method. How can one object of this class be synchronized? Luckily, the solution is simple: you simply put the call to the method defined by this class into a synchronized block.

The following is the general form of the synchronized statement:

Synchronized (object) {
  //statements to is synchronized
}

Where object is a reference to the objects being synchronized. If you want to sync with just one statement, then you don't need curly braces. A synchronization block ensures that calls to the object member method occur only after the current thread successfully enters the object tube.

The following is a modified version of the previous program with a synchronized block in the Run () method:

This is uses a synchronized block.
    Class Callme {void call (String msg) {System.out.print ("[" + msg);
    try {thread.sleep (1000);
    catch (Interruptedexception e) {System.out.println ("interrupted");
  } System.out.println ("]");
  Class Caller implements Runnable {String msg;
  Callme Target;
  Thread T;
    Public Caller (Callme Targ, String s) {target = Targ;
    msg = s;
    t = new Thread (this);
  T.start (); }//Synchronize calls to call () public void Run () {synchronized (target) {//synchronized block target.ca
    ll (msg);
    }} class Synch1 {public static void main (String args[]) {Callme target = new Callme ();
    Caller ob1 = new Caller (target, "Hello");
    Caller ob2 = new Caller (target, "Synchronized");

    Caller ob3 = new Caller (Target, "world");
      Wait for threads to end try {ob1.t.join ();
      Ob2.t.join ();
    Ob3.t.join (); The catch (Interruptedexception e) {SysTem.out.println ("interrupted");

 }
  }
}

Here, the call () method is not decorated by synchronized. Synchronized is declared in the run () method of the caller class. This results in the same correct result as in the previous example, because each thread waits for the previous thread to end before it runs.

Java Thread-Inter communication
Multithreading replaces the event loop program by dividing the task into discrete and logical units. Thread has a second advantage: it is far from polling. Polling is usually implemented by loops of repeated monitoring conditions. Once conditions are in place, appropriate action should be taken. This is a waste of CPU time. For example, consider a classic sequence problem when a thread is generating data and another program is consuming it. To make the problem more interesting, assume that the data generator must wait for the consumer to complete work before generating new data. In polling systems, consumers are wasting a lot of CPU cycles waiting for producers to generate data. Once the producer completes its work, it will start polling, wasting more CPU time waiting for the consumer's work to end, and so on. Obviously, this situation is not popular.

To avoid polling, Java contains a interprocess communication mechanism implemented through the wait (), notify (), and Notifyall () methods. These methods are implemented in the final method in the object, so all classes contain them. These three methods can be invoked only in the Synchronized method. Although these methods are highly advanced in concept from the perspective of computer science, they are very simple to use in practice:
Wait () tells the invoked thread to discard the pipe into sleep until the other thread enters the same pipe and calls notify ().
Notify () Restores the first thread in the same object that calls wait ().
Notifyall () Restores all threads that call wait () in the same object. The thread with the highest priority runs first.

These methods are declared in object, as follows:

  final void Wait () throws Interruptedexception
  final void notify ()
  final void Notifyall ()


Wait () Another form of existence allows you to define the waiting time.

The following example program incorrectly implements a Shantan/consumer problem. It consists of four classes: Q, trying to get synchronized sequences, Producer, generating queued thread objects, Consumer, consuming sequences of thread objects, and PCs, creating individual q,producer, and Consumer of small classes.

An incorrect implementation of a producer and consumer.
Class Q {
  int n;
  synchronized int get () {
    System.out.println ("Got:" + N);
    return n;
  }
  synchronized void put (int n) {
    THIS.N = n;
    System.out.println ("Put: + N");
  }
Class Producer implements Runnable {
  q q;
  Producer (q q) {
    this.q = q;
    New Thread (This, "Producer"). Start ();
  }
  public void Run () {
    int i = 0;
    while (true) {
      q.put (i++);
    }
}} Class Consumer implements Runnable {
  q q;
  Consumer (q q) {
    this.q = q;
    New Thread (This, "Consumer"). Start ();
  }
  public void Run () {while
    (true) {
      q.get ();
}}} Class PC {public
  static void Main (String args[]) {
    q q = new Q ();
    New Producer (q);
    New Consumer (q);
    System.out.println ("Press Control-c to Stop");
  }

Although the put () and get () methods in the Q class are synchronized, nothing prevents producers from exceeding the consumer, and nothing prevents consumers from consuming the same sequence two times. In this way, you get the following error output (the output will change with the processor speed and load Task):

Put:1
got:1
got:1
got:1
got:1
got:1
put:2 put:3 put:4 put:5 put:6
   put:7
Got:7

After the producer generates 1, the consumer obtains the same 15 times in turn. Producers continue to generate 2 to 7, and consumers have no chance of acquiring them.

Using Java to correctly write this program marks two directions with wait () and notify (), as follows:

A correct implementation of a producer and consumer.
  Class Q {int n;
  Boolean valueset = false;
      synchronized int get () {if (!valueset) try {wait ();
      catch (Interruptedexception e) {System.out.println ("interruptedexception caught");
      } System.out.println ("Got:" + N);
      Valueset = false;
      Notify ();
    return n;
      } synchronized void put (int n) {if (Valueset) try {wait ();
      catch (Interruptedexception e) {System.out.println ("interruptedexception caught");
      } THIS.N = n;
      Valueset = true;
      System.out.println ("Put:" + N);
    Notify ();
    } class Producer implements Runnable {q q;
    Producer (q q) {this.q = q;
  New Thread (This, "Producer"). Start ();
    public void Run () {int i = 0;
    while (true) {q.put (i++);
  }} class Consumer implements Runnable {q q;
    Consumer (q q) {this.q = q; New Thread (This, "ConsuMer "). Start ();
    public void Run () {while (true) {q.get ();
    }} class Pcfixed {public static void main (String args[]) {q q = new Q ();
    New Producer (q);
    New Consumer (q);
  System.out.println ("Press Control-c to stop");
 }
}

The internal get (), and wait () is invoked. This causes execution to hang until producer tells the data is ready. At this point, the internal get () is resumed. When the data is fetched, the Get () call Notify (). This tells producer that you can enter more data into the sequence. In put (), wait () suspends execution until consumer takes the item from the sequence. When execution continues, the next data item is placed in the sequence, notify () is invoked, which informs consumer that it should move the data.

The following is the output of the program, which clearly shows the synchronization behavior:

Put:1
got:1
put:2
got:2
put:3
got:3
put:4 got:4 put:5 got:5

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.