Java core technology to understand again--simple Java multithreading

Source: Internet
Author: User
Tags int size stub

, in the programming language, threading can be a love-hate paradox for programmers, which can greatly simplify the model, help programmers write powerful code, and, on the other hand, make our programs appear with a variety of bugs that can be difficult to reproduce in the development environment.

Here the author based on the "Java Core technology" book and some Bovinlai to share with you on Java multithreaded understanding and experience of processes and Threads

Before we learn, it is necessary to understand what processes and threads are. Process

The so-called process is the process of executing a program or task, and the process holds resources (memory, files) and threads. For example, we use the qq,eclipse and so on can be said to be the process. In particular, I would like to remind you that the process is the process of execution of a program or task , and that only when programs such as Eclipse are activated can they be called processes. So the process is a dynamic concept. Threads

We say that processes include resources and threads, so processes are the carrier of resources and threads, and it makes no sense to detach from the thread discussion process. So what is a thread. A program can often perform multiple tasks, and usually each task is called a thread. For example, there is a source code editor in eclipse that allows you to do a syntax check and compile our source code in the background.

So to sum up, we can sum up a few points: the thread is the smallest unit of execution in the system the same thread can contain the interaction of a resource thread in a process that has multiple thread threads sharing

Here, readers may already be familiar with multitasking in modern operating systems: the ability to run multiple programs at the same time. Multiple threads can work properly by communicating. This communication is what we call a thread's interaction. The way of interaction can be divided into two kinds: mutual exclusion and synchronization. For example, we compare a school to a process, and each student can be viewed as a thread. Then the behavior of cooperating with each other to accomplish some project or learning task can be understood as synchronization; there is a library in the school, when a classmate borrowed "Java core technology" from the library, and there is only one "Java core technology" in the library, then the classmate can not borrow this book, Only wait for the students to change the book back. This can be understood as mutual exclusion. Creation of Threads

Now let's talk about the creation of a thread. There are two common ways to create threads
-Inherit Java.lang.Thread
There is a run () method in this class. If the thread is constructed by a Runnable object, the Run () method in the Runnable object is called, otherwise the method should be overridden in the thread subclass. The instantiation of this thread is directly with new.
-Implement Java.lang.Runnable interface
Similarly, there is only one run () method in the interface.
When you create a thread using an object that implements the interface runnable, starting the thread invokes the run () method. Instantiating such a thread is a construction method of thread. As follows:

Thread (Runnable target) 
    thread (Runnable target, String name) 
    thread (threadgroup Group, Runnable target) 
    Thread (threadgroup group, Runnable Target, string name) 
    thread (threadgroup Group, Runnable Target, string name, long s Tacksize) '
start of Thread

Starts a thread, you only need to call the start () method in the Thread object. In fact, a thread calls the start () method, not to say that the thread is in the running state, where the author of the thread of the state does not do, in the following article will do a detailed description of the creation of the thread of the instance

The following is a small example to illustrate the creation of a thread:

Package Org.joea.java; public class Threaddemo extends Thread {public static void main (string[] args) {System.out.println (thread.c Urrentthread (). GetName () + "is the main thread."
        ");
        Thread Threaddemo = new Threaddemo ();

        Threaddemo.setname ("thread");//thread set name/start thread Threaddemo.start ();
        Creates a thread through the Runnable interface object and sets the thread name threads threadrunnable = new Thread (new Threadrunnabledemo (), "Runnable");
    Start thread Threadrunnable.start (); The//Rewrite run () method public void Run () {System.out.println (GetName () +) is an extended thread for thread.
        ");
        int count = 0;
        Boolean keyruning = true;
            while (keyruning) {System.out.println (GetName () + "Run" + (++count) + "Times");
            if (count = =) {keyruning = false;
                } if (count <=) {try {//Leave thread dormant for 1 seconds thread.sleep (1000);
              catch (Interruptedexception e) {      TODO auto-generated Catch block E.printstacktrace ();
    }} System.out.println (GetName () + "finished!");  } class Threadrunnabledemo implements Runnable {@Override public void run () {//TODO auto-generated Method Stub System.out.println (Thread.CurrentThread (). GetName () + "is a thread that implements the Runnable interface.
        ");
        int count = 0;
        Boolean keyruning = true; while (keyruning) {System.out.println (Thread.CurrentThread (). GetName () + "Run" + (++count
            ) + "Times");
            if (count = =) {keyruning = false;
                } if (count <=) {try {//Leave thread dormant for 1 seconds thread.sleep (1000); catch (Interruptedexception e) {//TODO auto-generated catch block e.prints
                Tacktrace (); }}} SysteM.out.println (Thread.CurrentThread (). GetName () + "End!");
 }

}

The above code demonstrates two ways to create a thread in Java, from the above code we can get the following:
-The thread can either set the name or get the name of the thread. The name of the thread can be either the programmer's own decision or the JVM's own.
-Threads in the above code can only guarantee that each thread can start and run to the end. But for any group (two or more) threads, can not guarantee its order of operation, running time is not guaranteed (here is a preemptive scheduling principle, after the article will be introduced).
-Usually when the run () method in the thread ends, meaning that the end of the thread is synchronized

In most practical multi-threaded applications, two or more than two threads need to share access to the same data. Imagine if all two processes call the same method that modifies the data in the database, which may result in unexpected errors from the modified data.
For example: The simulation has a bank. There are n accounts, each account has a thread, in each transaction, will be transferred from the thread's account to another account of the random amount of money.
Banktest.java

Package org.javathread.joea;

public class Banktest {public

    static final int naccounts=100;
    public static final double initial_balabce=100;

    public static void Main (string[] args) {
        Bank b=new Bank (naccounts, INITIAL_BALABCE);
        int i;
        for (i=0;i<naccounts;i++) {
            transferrunnable r=new transferrunnable (b, I, INITIAL_BALABCE);
            Thread t=new thread (r);
            T.start ();}}

Bank.java

 Package org.javathread.joea;

    public class Bank {private final double[] accounts; /** * * @param n * Number of users * @param initialbalance * User initial deposit/Publi
        c Bank (int n, double initialbalance) {accounts = new double[n];
        for (int i = 0; i < accounts.length i++) {accounts[i] = initialbalance;

    }/** * Transfer the money from the from account to the to account * @param from the transfer out account * @param to the account * @param amount the number of transfers * *
        public void transfer (int from, int to, double amount) {if (Accounts[from] < amount) {return;
        } System.out.println (Thread.CurrentThread ());
        Accounts[from]-= amount;
        System.out.printf ("%10.2f from%d to%d", amount, from, to);
        Accounts[to] + = amount;
    System.out.printf ("Totle Balance:%10.2f%n", gettotalbalance ()); /** * Recalculate the total value of the data in the bank * @return Sum of money * * Private double GettotalbaLance () {double sum = 0;
        for (double a:accounts) sum = A;
    return sum;
    /** * Number of users * @return Number of users * * public int size () {return accounts.length; }
}

Transferrunnable.java

Package org.javathread.joea;

/**
 * Analog user transfer thread
 * * 
 @author joea * */Public
class Transferrunnable implements Runnable {

    Private Bank bank;
    private int fromaccount;
    Private double maxamount;
    Private final int DELAY = ten;

    Public transferrunnable (Bank b, int from, double max) {

        Bank = b;
        Fromaccount = from;
        Maxamount = max;
    }

    @Override public
    Void Run () {
        //TODO auto-generated a stub
        try {while
            (true) {
                int Toacco UNT = (int) (Bank.size () * math.random ());
                Double amount = Maxamount * Math.random ();
                Bank.transfer (Fromaccount, Toaccount, amount);
                Thread.Sleep (DELAY);
            }
        catch (Interruptedexception e) {
            //Todo:handle exception
        }

    }

}

The code above is to transfer a certain amount of money from one account to another by calling the transfer method in the Bank class. Then, through the Run method in the Transferrunnable class, a certain amount of money is randomly removed from the bank from one account, and a random target account is selected for the transfer. The results of the operation are as follows:

  52.39 90Totle Balance:  10000.00 
Thread[thread-55,5,main] 86.58 from-to
     15Totle Balance:  10 000.00 
Thread[thread-7,5,main]
     44.79 from 7 to 77Totle Balance:  10000.00 
Thread[thread-30,5,main]
     14.38 from to 22Totle Balance:  10000.00 
thread[thread-53,5,main]
...
Thread[thread-78,5,main]
     34.40 from 61Totle Balance:   9912.33 
Thread[thread-1,5,main]
     42.24 from 1 to 46Totle Balance:   9912.33 
Thread[thread-70,5,main]
     27.56 from to 69Totle Balance:   

Here we find a slight change in the total amount of money in the bank. Looking at our code, we will find that although we have made mutual transfers to the accounts in the bank, we have not changed the total amount of money in the bank. But there was an unexpected mistake. This is why.
Here we analyze the transfer process in our program: Get the target account Account[to] increase the amount of amount money to write the results back to Account[to]
Now we assume that a thread K has got account[i], and just finished step 2, and then it is stripped of the right to run. Then another thread h is awakened and modifies the value in Account[i], and the K-line is awakened and completes the third step. So the total number is no longer correct. lock objects and condition objects Lock Object

There are two mechanisms in Java that prevent code from being affected by concurrent access. Here we introduce the lock object and the Condition object first.
The Java.util.concurrent framework provides us with a lock interface and introduces a class--reentrantlock class that inherits the lock interface.
Let's first use a lock to protect the transfer method in the bank:

public class Bank {

    private Lock Banklock = new Reentrantlock ();
    public void transfer (int from, int to, double amount) {
        if (Accounts[from] < amount) {return
            ;
        }
        Banklock.lock ();
        try {
            System.out.println (Thread.CurrentThread ());
            Accounts[from]-= amount;
            System.out.printf ("%10.2f from%d to%d", amount, from, to);
            Accounts[to] + = amount;
            System.out.printf ("Totle Balance:%10.2f%n", gettotalbalance ());
        finally {
            banklock.unlock ();}}


This is when we run the code again and we find that the total amount of money in the bank does not change. This is because once a thread has blocked the lock object, no other thread can pass the lock statement and will go into a blocking state until the first thread releases the lock object. So when a thread invokes transfer, even if it is stripped of the right to run before execution ends, the second thread that calls transfer cannot get the lock object. It must wait for the first thread to release the lock object. Condition Object

Look at our transfer code again:

public void transfer (int from, int to, double amount) {
        if (Accounts[from] < amount) {return
            ;
        }
    ....
    }

When we are transferring the money out of the account less than amount we are not taking any action. Here we refine the program. We avoid choosing an account that does not have sufficient funds as a transfer account. And make sure that no other thread modifies the balance between the balance and the transfer operation on this thread. So through the lock object to protect the detection balance and transfer operation:

public void transfer (int from, int to, double amount) {
        banklock.lock ();
        try {while
            (accounts[from]<amount) {
                ...
            }
            ....
        } finally {
            banklock.unlock ();
        }
    }

When a thread finds that the balance is insufficient, we want the thread to wait until another thread has injected enough money into the account. However, this thread has just acquired exclusive access to the Banklock, so other threads do not have access to the account. This is why the conditional object is introduced.

A lock object may have more than one condition object. We can use the Newcondition method to get a condition object. When the object discovers that the thread's running conditions are not met, the await () method is invoked to cause the current thread to enter a blocking state and the lock is discarded. For example, the await () method is invoked when the transfer method discovers that the balance in the account is insufficient. Wait for another thread to add the balance to the account. Once a thread invokes the await method, it enters the waiting set for that condition. When a lock is available, the thread cannot immediately unblock the state until another thread invokes the Signalall method on the same condition. At this point, the thread detects the condition again.
The last code in our Bank.java is as follows:

Package org.javathread.joea;
Import java.util.concurrent.locks.Condition;
Import Java.util.concurrent.locks.Lock;

Import Java.util.concurrent.locks.ReentrantLock;
    public class Bank {private Lock banklock;

    private Condition sufficient;

    Private final double[] accounts; /** * * @param n * Number of users * @param initialbalance * User initial deposit/Publi
        c Bank (int n, double initialbalance) {accounts = new double[n];
        for (int i = 0; i < accounts.length i++) {accounts[i] = initialbalance;

        } Banklock = new Reentrantlock ();
     sufficient = Banklock.newcondition ()//Get a condition associated with the lock F}/** * Transfer money from the from account to the to account * @param from * Transfer out of account * @param to * transfer to account * @param amount * @throws inte Rruptedexception */public void transfer (int from, int to, double amount) throws Interruptedexception {
        Banklock.lock ();
            try {while (Accounts[from] < amount) {sufficient.await ();//insufficient balance, enter blocking state}
            System.out.println (Thread.CurrentThread ());
            Accounts[from]-= amount;
            System.out.printf ("%10.2f from%d to%d", amount, from, to);
            Accounts[to] + = amount;
            System.out.printf ("Totle Balance:%10.2f%n", gettotalbalance ());
        Sufficient.signalall ();//Wake up condition waiting for all threads} finally {Banklock.unlock (); /** * Recalculate the total value of the data in the bank * * @return Sum of money * * Private double gettotalbalance () {D
        Ouble sum = 0;
        for (double a:accounts) sum = A;
    return sum;
    /** * Number of users * * @return Number of users * * public int size () {return accounts.length;
 }
}

Let's summarize the key to the lock and the condition: the lock object guarantees that only one thread can execute a protected code lock at any point in time. You may have one or more related conditional object locks to manage threads that attempt to enter the protected code Each condition object manages a thread synchronized keyword that has entered the protected code but is not yet able to run

Although the lock and condition interfaces provide a high degree of lock control for programmers. However, in fact starting from Java 1.0, each object has an internal lock. If a method is declared with the Synchronized keyword. Then the lock of the object protects the entire method.
Internal locks have only one related condition. The wait method adds a thread to the waiting set. The Notify and Notifyall methods touch the blocking state of the waiting thread.
The bank method decorated with synchronized is as follows:

Package org.javathread.joea;

    public class Bank {private final double[] accounts; /** * * @param n * Number of users * @param initialbalance * User initial deposit/Publi
        c Bank (int n, double initialbalance) {accounts = new double[n];
        for (int i = 0; i < accounts.length i++) {accounts[i] = initialbalance;
}//Banklock = new Reentrantlock ();  sufficient = Banklock.newcondition ()//obtain a condition associated with the lock F}/** * Transfer money from the from account to the to account * *
     @param from * transfer out of account * @param to * transfer to account * @param amount * Number of transfers * @throws interruptedexception */public synchronized void transfer (int from, int to, double amount) throws
            interruptedexception {while (Accounts[from] < amount) {wait ();//The balance is not enough to enter the blocking state
            } System.out.println (Thread.CurrentThread ()); AccouNts[from]-= amount;
            System.out.printf ("%10.2f from%d to%d", amount, from, to);
            Accounts[to] + = amount;
            System.out.printf ("Totle Balance:%10.2f%n", gettotalbalance ()); 
     Sufficient.signalall ();//Wakeup conditions wait for all threads notifyall ();//Wake up conditions wait for all threads}/** * Recalculate the total value of the data in the bank *
        * Total @return sum of money/private synchronized Double gettotalbalance () {double sum = 0;
        for (double a:accounts) sum = A;
    return sum;
    /** * Number of users * * @return Number of users * * public int size () {return accounts.length;
 }
}

You can see that using the Synchronized keyword to write code is much simpler. Of course, to understand this code, you have to understand the lock object and the Condition object. But there are some limitations to this internal lock. For example, when a thread tries to acquire a lock, it cannot set a timeout condition; the condition of each lock is single, it may not be enough; you cannot break a thread that is trying to acquire a lock.

There is a lot of knowledge about threads, knowing that they only learn some of the fur of threads. Later articles will continue to learn and share the experience of threading and synchronized learning.
Above.

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.