Communication between threads

Source: Internet
Author: User
Tags int size stub visibility volatile

Reference:
How to communicate between threads in Java multi-thread
Java thread and thread, process and interprocess communication
The above two blogs were sorted out, and the experiment code was run under JDK8 to test.

How to communicate between threads:
1. Shared variables
2. Wait/notify mechanism
3. Lock/condition mechanism
4. Pipe mode One, share variable/shared Memory (synchronized)

Synchronization here refers to the way multiple threads use the Synchronized keyword to communicate between threads.

Package testcode;


public class MyObject {

    synchronized public void MethodA () {
        //do something ....
        System.out.println ("A");
    }

    Synchronized public void MethodB () {
        //do some the other thing
        System.out.println ("B");
    }

Package testcode;

public class Threada extends Thread {

    private MyObject object;
Public Threada (MyObject object2) {
        //TODO auto-generated constructor stub
    this.object = Object2;
    }
    Omitting the construction method
    @Override public
    void Run () {
        super.run ();
        Object.methoda ();
    }

Package testcode;

public class Threadb extends Thread {

    private MyObject object;
Public threadb (MyObject object2) {
        //TODO auto-generated constructor stub
    this.object = Object2;
    }
    Omitting the construction method
    @Override public
    void Run () {
        super.run ();
        Object.methodb ();
    }
Package testcode;

public class Run {public
    static void Main (string[] args) {
        MyObject object = new MyObject ();

        Thread A and thread B hold the same object: Object
        Threada a = new Threada (object);
        THREADB B = new Threadb (object);
        A.start ();
        B.start ();
    }

Run Result:

A
B
Because thread A and thread B hold object objects of the same MyObject class, although the two threads need to invoke different methods, they are executed synchronously, for example: thread B needs to wait for thread A to execute the MethodA () method before it executes the MethodB () method. This enables both thread A and thread B to communicate.

This way, in essence, is the " Shared memory " type of communication. Multiple threads need access to the same shared variable, who gets the lock (access rights), and who can execute it. mode One, Shared Memory (while polling way)

Package testcode;

Import java.util.ArrayList;
Import java.util.List;

public class MyList {

    private list<string> List = new arraylist<string> ();
    public void Add () {
        list.add ("elements");
    }
    public int size () {return
        list.size ();
    }
}
package testcode;

    public class Threada extends Thread {private MyList list;
        Public Threada (MyList list) {super ();
    This.list = list; @Override public void Run () {try {= 0; I < i++) {list.
                Add ();
                System.out.println ("added" + (i + 1) + "element");
            Thread.Sleep (1000);
        } catch (Interruptedexception e) {e.printstacktrace (); }
    }
}
Package testcode;

public class Threadb extends Thread {

    private MyList list;

    Public threadb (MyList list) {
        super ();
        this.list = list;
    }

    @Override public
    Void Run () {a
        try {while
            (true) {
                if (list.size () = = 5) {
                    System.out.println ("==5 , thread B is ready to quit ");
                    throw new Interruptedexception ();}}
        catch (Interruptedexception e) {
            e.printstacktrace ();}}}
public class Run {public
     static void Main (string[] args) {
            MyList list = new MyList ();

            Threada a = new Threada (list);
            A.setname ("A");
            A.start ();

            THREADB B = new threadb (list);
            B.setname ("B");
            B.start ();
        }

Run Result:

1 elements added
2 elements added
3 elements added
4 elements added
5 elements added
6 elements added
7 elements added
8 elements added
9 elements added
10 elements added
Fall into the cycle of death ....

In this way, thread a constantly changes the condition, and the thread threadb to detect whether the condition (list.size () ==5) is established through the while statement, thus enabling the communication between threads. But this approach wastes CPU resources. It is a waste of resources because the JVM Scheduler is not doing "useful" work when the CPU is handed over to thread B, but is constantly testing whether a condition is true or not. Just like in real life, someone has been looking at the phone screen to see if there is a phone, instead of: doing something else, when there is a call, the bell to notify Ta phone. About the impact of thread polling, refer to: Java multithreading when a thread is executing a dead loop, it affects another thread.

There is another problem with this approach:

Visibility issues for polling conditions, regarding memory visibility issues, refer to: Java multi-line volatile and synchronized in the comparison of the 1th "one, volatile the visibility of the keyword"

Threads are the first to read the variables to the local line stacks space, and then go to modify the local variables. Therefore, if thread B takes a local condition variable every time, then even though another thread has changed the condition of polling, it will not be aware of it, which can also cause a dead loop. mode two, wait/notify mechanism

package testcode;
Import java.util.ArrayList;

Import java.util.List;
    public class MyList {private static list<string> List = new arraylist<string> ();
    public static void Add () {List.add ("elements");
    public static int size () {return list.size (); }
}
package testcode;

    public class Threada extends Thread {private Object lock;
        Public Threada (Object Lock) {super ();
    This.lock = lock;  @Override public void Run () {try {synchronized (lock) {if mylist.size ()
                    != 5) {System.out.println ("wait Begin" + system.currenttimemillis ());
                    Lock.wait ();
                SYSTEM.OUT.PRINTLN ("Wait End" + system.currenttimemillis ());
        A catch (Interruptedexception e) {e.printstacktrace ()); }
    }
}
package testcode;

        public class Threadb extends Thread {private Object lock;
            Public threadb (Object Lock) {super ();
        This.lock = lock;
                    @Override public void Run () {try {synchronized (lock) {
                        for (int i = 0; i < i++) {mylist.add ();
                            if (mylist.size () = = 5) {lock.notify ();
                        System.out.println ("The notice has been issued");
                        System.out.println ("added" + (i + 1) + "Element!");
                    Thread.Sleep (1000);
            A catch (Interruptedexception e) {e.printstacktrace ()); }
        }
}
Package testcode;

public class Run {public
     static void Main (string[] args) {

            try {
                object lock = new Object ();

                Threada a = new Threada (lock);
                A.start ();

                Thread.Sleep (m);

                THREADB B = new threadb (lock);
                B.start ();
            } catch (Interruptedexception e) {
                e.printstacktrace ();}}}

Run Result:

Wait begin 1504599622985
Added 1 elements!
Added 2 elements!
Added 3 elements!
Added 4 elements!
A notice has been sent
Added 5 elements!
Added 6 elements!
Added 7 elements!
Added 8 elements!
Added 9 elements!
Added 10 elements!
Wait End 1504599633035

The action is performed when thread a waits for a condition to be satisfied (List.size () ==5). Thread B adds the element to the list, changing the size of the list.

A,b how to communicate with each other. In other words, how thread a knows that list.size () is already 5.

Here we use the wait () and the Notify () method of the object class.

When the condition is not met (List.size ()!=5), thread A calls wait () to discard the CPU and enter the blocking state. -Do not consume CPU as ②while polling

When the condition is met, thread B calls the Notify () notification thread A, the so-called notification thread A, which wakes up thread A and lets it into a running state.

One advantage of this approach is that CPU utilization has increased.

But there are some drawbacks: for example, thread B executes first, adds 5 elements at a time and invokes notify () to send a notification, while thread A also executes, and when thread a executes and invokes wait (), it never wakes up. Because, thread B has been notified, and will not be notified later. This means that the notification is premature and disrupts the execution logic of the program. methods Third, pipeline communication

is to use Java.io.PipedInputStream and java.io.PipedOutputStream for communication.

Pipeline flow is one of the common ways of Java thread Communication, and the basic flow is as follows:

1 Create pipeline output stream PipedOutputStream pos and pipe input stream PipedInputStream PiS

2) to match POS and PiS, Pos.connect (PiS);

3 The POS will be assigned to the information input thread, PiS to the information to obtain the thread, you can implement the communication between the threads

and pipeline communication, more like messaging mechanism, that is to say: Through the pipeline, the message sent to another thread.

Package testcode;
Import java.io.IOException;
Import Java.io.PipedInputStream;

Import Java.io.PipedOutputStream; 
        public class Testpipeconnection {public static void main (string[] args) {/** * Create pipe output stream * *
        PipedOutputStream pos = new PipedOutputStream ();
        /** * Create pipeline input stream * * PipedInputStream pis = new PipedInputStream ();
        try {/** * The pipeline inflow and output are connected to the process can also be implemented through the overload of the constructor Pos.connect (PiS);
        catch (IOException e) {e.printstacktrace ();
        /** * Create producer Thread */Producer p = new Producer (POS);
        /** * Create Consumer thread * * * Consumer1 c1 = new Consumer1 (PiS);
        /** * Start thread/p.start ();
    C1.start ();

    }/** * Producer thread (associated with a pipe output stream) */class Producer extends Thread {private PipedOutputStream pos;
    Public Producer (PipedOutputStream POS) {    This.pos = pos;
        public void Run () {int i = 0;
            try {while (true) {This.sleep (3000);
            System.out.println ("producer:" +i);
            Pos.write (i);
            i++;
        } catch (Exception e) {e.printstacktrace ();

    }}/** * Consumer thread (associated with a pipeline input) */class Consumer1 extends thread {private PipedInputStream pis;
    Public Consumer1 (PipedInputStream pis) {this.pis = PiS; public void Run () {try {while (true) {System.out.println ("Consumer1:")
            +pis.read ());
        } catch (IOException e) {e.printstacktrace (); }
    }
}

You can see the producer thread sending data to the CONSUMER1 thread:

producer:0
consumer1:0
Producer:1
Consumer1:1
Producer:2
Consumer1:2
Producer:3
Consumer1:3
Producer:4
Consumer1:4
Producer:5
Consumer1:5
Producer:6

Although the flow of piping is convenient to use, there are some drawbacks

1 pipeline flow can only pass data between two threads

Threads Consumer1 and Consumer2 read data from PiS at the same time, and when the thread producer writes a piece of data to the pipe stream, only one thread at a time can get the data, and not two threads can get the data that the producer sent. Therefore, a pipe flow can only be used for communication between two threads . More than just pipe flow, other IO methods are transmitted on a one-to-one basis.

2 pipeline flow can only achieve one-way transmission , if you want to communicate between two threads, you need two pipeline flow (Half-duplex)

As you can see in the example above, thread producer sends data through a pipe flow to the thread consumer, and if the thread consumer want to send data to the thread producer, you need to create another pipeline stream POS1 and Pis1 and assign POS1 to Consumer1. PIS1 will be assigned to producer, the specific example of this article no longer said. methods Four, lock/condition mechanism (synchronous one)

If the program does not use the Synchronized keyword to maintain synchronization, but instead applies the lock pair image directly to keep the synchronization, there is no implicit synchronization monitor object in the system and you cannot use Wait (), notify (), notifyall () to coordinate the running of the thread.

When using the lock object to maintain synchronization, Java provides us with a condition class to coordinate the running of threads. For the condition class, the JDK documentation is explained in detail.

Suppose there are two threads in the system, each representing the money-taking and the person who saved it. Now the system has a special requirement, the system requires depositors and money-seekers to continuously implement deposits and withdraw money, and requires that the person who takes the money is immediately taken away when the depositor deposits the money in the designated account. The depositor is not allowed to save two times and does not allow the person to withdraw money two times.
We set a flag to identify whether there is a deposit in the account, is true, and no is marked false. The specific code is as follows:

First we define the account class, which has two methods for getting and saving money, since these two methods may require concurrent execution to withdraw money, save operations, and all modify both methods to a synchronized method. (using the Synchronized keyword).

Package testcode;  
Import java.util.concurrent.locks.Condition;  
Import Java.util.concurrent.locks.Lock;  

Import Java.util.concurrent.locks.ReentrantLock;  
    public class Account {//Show definition Lock object private final lock lock=new Reentrantlock ();     

    Gets the specified lock object's corresponding condition variable private final Condition con=lock.newcondition ();  
    Private String Accountno;  
    private double balance;  

    Flag Private Boolean Flag=false that identifies whether there is a deposit in the account;  
    Public account () {super ();  
        } Public account (String Accountno, double balance) {super ();  
        This.accountno = Accountno;  
    This.balance = balance;  
        public void Draw (double drawamount) {//Lock lock.lock ();  
              try {if (!flag) {//this.wait ();  
             Con.await ();   
      }else {//System.out.println (Thread.CurrentThread (). GetName () + "Withdraw money:" +drawamount);           Balance=balance-drawamount;  
                 System.out.println ("Balance:" +balance);  
                 To set the mark of whether the account has deposit is false flag=false;    
                 Wake up Other threads//This.notifyall ();  
             Con.signalall ();  
        } catch (Exception e) {e.printstacktrace ();  
            } finally{Lock.unlock ();  
       } public void deposit (double depositamount) {//Lock lock.lock ();  
                  try {if (flag) {//this.wait ();  
              Con.await ();  
                  } else{System.out.println (Thread.CurrentThread (). GetName () + "save Money" +depositamount);  
                  Balance=balance+depositamount;  
                  System.out.println ("Account balance is:" +balance);  
                  Flag=true;  
         Wake up Other threads//This.notifyall ();         Con.signalall ();  
        } catch (Exception e) {//Todo:handle Exception e.printstacktrace ();  
        }finally{Lock.unlock ();   }  
   }  

}
Package testcode;

public class Drawthread implements Runnable {  

    private account account;  
    Private double drawamount;  


    Public Drawthread (account account, double drawamount) {  
        super ();  
        This.account = account;  
        This.drawamount = Drawamount;  
    }  

    public void Run () {for  
        (int i=0;i<4;i++) {  
           account.draw (drawamount);      
        }  
    }  
Package testcode;

public class Depositthread implements Runnable {

    private account account;  
    Private double depositamount;  


    Public Depositthread (account account, double drawamount) {  
        super ();  
        This.account = account;  
        This.depositamount = Drawamount;  
    }  

    public void Run () {for  
        (int i=0;i<5;i++) {  
           account.deposit (depositamount);      
        }  
    }  

}
Package testcode;

public class Run {public
    static void Main (string[] args) {  
        //Create an account  
        account=new accounts ();  
        New Thread (New Drawthread (account, 800), "money-taking"). Start ();  
        New Thread (account, 800), "Depositthread". Start ();  
        New Thread (account, 800), "depositor B". Start ();  
        Depositthread New Thread (account, 800), "depositor C"). Start ();  

    }  
}

Run Result:

Depositor a saves 800.0
Account balance is: 800.0
Withdraw money to withdraw money: 800.0
Balance: 0.0
Depositor b saves 800.0
Account balance is: 800.0
Withdraw money to withdraw money: 800.0
Balance: 0.0
Depositor a saves 800.0
Account balance is: 800.0
Withdraw money to withdraw money: 800.0
Balance: 0.0
Depositor a saves 800.0
Account balance is: 800.0

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.