Java Multithreading Basics

Source: Internet
Author: User
Tags deprecated terminates visibility volatile

Java Multithreading Basics

@ (blog post) [Java]

    • Java Multithreading Basics
    • An overview
      • A basic content
        • 1 Basic concepts of threading
        • 2JAVA Thread Basics
        • 3 2 ways to create a new thread
      • The state of the second process and its change
        • Six states of 1Java threads
        • 2 changes in thread state
    • Three common APIs
      • 11 Creating a Startup thread
      • Two ways to terminate a thread
      • Three-thread priority
      • Four Waitnofitynotifyall
      • Five deprecated APIs
      • Six Daemon threads
      • Seven sleep
      • Eight volatile
      • Nine synchronized
      • Ten threadlocal
          • An example
          • How to create a threadlocal variable
          • How to access the threadlocal variable
          • How to initialize the value of a threadlocal variable
          • Know it
          • Know the reason why
      • 11 Join

I. Overview (i) basic content 1, thread concept

(1) A thread is a sequential control flow within a program.

(2) Threads and processes
– Each process has a separate code and data space (process context), and the process switching overhead is high.

– Threads: A lightweight process that shares code and data spaces with a class of threads, each with a separate run stack and program counter (PC), with minimal thread switching overhead.

– Multi-process: In the operating system, multiple tasks (Programs) can be run concurrently.

– Multithreading: In the same application, there are multiple sequential streams executing simultaneously.

(3) There are generally 2 ways to communicate between threads: Shared memory and message delivery. In the shared-memory model, multiple threads implement implicit communication by reading and writing variables in public memory. In the messaging model, there is no public state between threads, and threads must communicate explicitly by sending messages.

Java primarily uses shared memory for thread communication, and public variables are stored in heap memory in the JVM, where multiple threads can access the memory content at the same time. Repeat, the heap is mainly stored in class instance variables, static variables, arrays, etc., while the stack holds local variables, parameters and so on.
But Java also has some message-passing scenarios, such as notify.

2. Java Threading Basics

Java threads are implemented through the Java.lang.Thread class.

The VM starts with a thread defined by the main () method.

You can create a new thread by creating an instance of the thread.

Each thread completes its operation by means of the method run () that corresponds to a particular thread object, and the method run () is called the thread body.

Start a thread by calling the start () method of the thread class.

3.2 ways to create a new thread

(1) Inherit the thread class

(2) Implement Runnable interface

The second way to implement the Runnable interface is recommended.

(ii) thread state and its Evolution 1. Six states of Java threads
Status Name Description
NEW The initial state, the thread was built, but the start () method was not called yet.
RUNNABLE Running state, Java threads unify the two states of readiness and operation in the operating system as rannable
BLOCK Blocking state, indicating that the thread is blocking the lock
Waiting Wait state, indicating that the current thread needs to wait for other threads to make some pending actions (notifications or interrupts)
Time_waiting Timeout wait state, similar to waiting, but can be returned by itself after a specified time
TERMINATED Terminating state, indicating that the current thread has finished executing
2. Changes in thread state

Iii. Common API (i) 1, create & Start thread

The process needs to implement the Runnable interface or inherit the thread class, typically using the former. Then create a thread object and call its start () method.

public class CreateThread {    public static void main(String[] args) {        //2、使用线程类创建一个线程对象        PrintDate pd = new PrintDate();        Thread t = new Thread(pd);        //3、启动线程        t.start();    }}//1、创建线程类class PrintDate implements Runnable {    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(new Date());        }    }}
(ii) method of terminating a thread

When all the code in a thread is executed, the thread terminates. However, in many cases, the thread's Run () method uses a loop to execute until it explicitly notifies it that the thread has terminated. There are 2 ways to notify the thread to terminate: (1) Use a Boolean value to notify the thread (2) to use the thread's interrupt standard bit.

public class TerminateThread {    public static void main(String[] args) throws InterruptedException {        //1、使用interrupt()方法终止线程        Runner runnerOne = new Runner();        Thread threadOne = new Thread(runnerOne);        threadOne.start();        Thread.sleep(5000);        threadOne.interrupt();        //2、使用boolean对象终止线程        Runner runnerTwo = new Runner();        Thread threadTwo = new Thread(runnerTwo);        threadTwo.start();        Thread.sleep(5000);        runnerTwo.cancle();    }}class Runner implements Runnable {    private static boolean on = true;    @Override    public void run() {        while (on && !Thread.currentThread().isInterrupted()) {            System.out.println("Current time is " + Calendar.getInstance().getTime());        }    }    public void cancle() {        on = false;    }}
(iii) Thread priority

You can prioritize threads so that some threads can take precedence, but do not rely on the priority of the thread because different systems handle thread priorities differently, and some systems even ignore thread priorities.

public class ThreadPriority {    public static void main(String[] args) {        Runnable r = new MyThread();        Thread t = new Thread(r,"t1");        System.out.println(t.getPriority());//默认优先级为5        System.out.println(Thread.MAX_PRIORITY);//最大优先级为10        System.out.println(Thread.MIN_PRIORITY);//最小优先级为1        t.setPriority(Thread.MIN_PRIORITY);        t.start();        Thread t2 = new Thread(r,"t2");        t2.start();        Thread t3 = new Thread(r,"t3");        t3.setPriority(Thread.MAX_PRIORITY);        t3.start();    }}class MyThread implements Runnable{    public void run() {        for(int i = 0; i < 100; i++){            System.out.println(Thread.currentThread().getName());        }    }}
(iv) Wait ()/nofity ()/notifyall ()

All 3 of these methods are defined in object, that is, any Java object has these 3 objects.
A classic application is the producer consumer model. When the consumer consumes the message, if no message is found, the Wait () method waits for production, and the producer calls notify ()/notifyall () to notify the consumer when the message is finished.

(v) Some deprecated APIs

Stop () replaces with interrupt ()
Susppend () Replace with wait ()
Resume () replaces with nofity ()/nofityall ()

After these old APIs are invoked, the thread does not release the resources that are already occupied (such as locks), which can easily cause deadlocks.

(vi) Daemon thread

The daemon thread is used to complete a supporting thread, but the finally module in the daemon thread is not necessarily executed at the time the JVM exits, so it cannot rely on the contents of the daemon thread's finally to close or clean up the resource.
Here's how to set up the daemon thread:

thread.setDaemon(true);

When a non-daemon thread does not exist in a JVM, the JVM exits.

(vii) Sleep ()

Thead.sleep (long) will sleep for a while, but if the interrupt () method of the thread is called during this time, the interruptedexception will be thrown and the INTERRUPTE flag bit will be restored.

(eight) volatile

Java supports multiple threads accessing an object or a member variable of an object at the same time, because each thread can have a copy of the variable (although the object and the memory allocated by the member variable are in shared memory, each executing thread can still have a copy, which is intended to speed up the execution of the program. This is a significant feature of modern multicore processors, so the variables that a thread sees during execution are not necessarily up-to-date.
The keyword volatile can be used to modify a field (member variable), that is, to tell the program that any access to the variable needs to be fetched from shared memory, and that changes must be flushed back to shared memory synchronously, which guarantees the visibility of variable access for all threads.
However, excessive use of volatile is unnecessary because it reduces the efficiency of program execution.

For more information, refer to: http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

* Volatile variables in the Java language can be thought of as a "light synchronized"; * volatile variables require less coding and run-time overhead than synchronized blocks. But the functionality it can achieve is only part of the synchronized. This article describes several patterns for using volatile variables effectively, and highlights several scenarios where volatile variables are not appropriate.

The lock provides two main features: Mutual exclusion (mutual exclusion) and visibility (visibility). Mutual exclusion allows only one thread to hold a particular lock at a time, so you can use this attribute to implement a coordinated access protocol to shared data so that only one thread can use that shared data at a time. Visibility is more complex, and it must ensure that the changes made to the shared data before the lock is released are visible to the other thread that subsequently acquired the lock-if there is no guarantee of this visibility provided by the synchronization mechanism, the shared variables that the thread sees may be pre-modified or inconsistent values, which can cause many serious problems.

Volatile variables have synchronized visibility characteristics, but they do not have atomic properties. This means that threads can automatically discover the latest values of volatile variables. Volatile variables can be used to provide thread safety, but can only be applied to a very limited set of use cases: there is no constraint between multiple variables or between the current value of a variable and the modified value. Therefore, using volatile alone is not sufficient to implement counters, mutexes, or any class that has invariant (invariants) associated with multiple variables (for example, "Start <=end").

(ix) Synchronized

Synchronized can be modified or used as a synchronous block, it mainly ensures that multiple threads at the same time, only one thread is in the method or synchronous fast, it guarantees the visibility of the variable access of the thread and its exclusive nature.
Any object has its own monitor, and when the object is called by a synchronous block or a synchronous method of the object, the thread that executes the method must first acquire the monitor of the object to enter the synchronization block or the synchronization method. Threads that do not get to monitor will be blocked at the entrance to the synchronization block or synchronization method, entering the blocked state.

(10) ThreadLocal

ThreadLocal, a thread variable, is a storage structure that takes a ThreadLocal object to a key and any object as a value. This structure is attached to the thread, which means that a thread can query a Threadlocal object to a value that is bound on the threads. For example, the connection of specifying a database for each thread is described in the following examples.
You can set a value through set (T), and then get the value that you set by using get () under the current thread.

The Threadlocal class in Java allows us to create variables that can be read and written only by the same thread. Therefore, if a piece of code contains a reference to a threadlocal variable, even if two threads execute the code at the same time, they cannot access the other's threadlocal variable.

An example
public static void main(String[] args) throws InterruptedException {    Runnable shareRunnableInstance = new MyRunnable();    Thread t1 = new Thread(shareRunnableInstance);    Thread t2 = new Thread(shareRunnableInstance);    t1.start();    Thread.sleep(5000);    t2.start();}}class MyRunnable implements Runnable {    private ThreadLocal<Long> threadCreateTime = new ThreadLocal<Long>() {        @Override        protected Long initialValue() {            return 0L;        }    };    @Override    public void run() {        threadCreateTime.set(System.currentTimeMillis());        System.out.println(threadCreateTime.get());    }}

The above example creates a threadlocal variable to record the creation time of a thread, and it only needs to create a Runnable object to create multiple threads using the same object, which is an important application of threadlocal. In fact, if you create multiple Runnable objects, you can do the same thing without using threadlocal, because each Runnable object has its own independent variable:

public class ThreadLocalDemo {    public static void main(String[] args) throws InterruptedException {        Runnable r1 = new MyRunnable2();        Runnable r2 = new MyRunnable2();        Thread t3 = new Thread(r1);        Thread t4 = new Thread(r2);        t3.start();        Thread.sleep(5000);        t4.start();    }}class MyRunnable2 implements Runnable {    private Long threadCreateTime = 0L;    @Override    public void run() {        threadCreateTime = System.currentTimeMillis();        System.out.println(threadCreateTime);    }}
How to create a threadlocal variable

The following code shows how to create a threadlocal variable:

private ThreadLocal myThreadLocal = new ThreadLocal();

As we can see, a Threadlocal object is instantiated by this piece of code. We only need to instantiate the object once, and we don't need to know which thread it was instantiated by. Although all threads have access to this threadlocal instance, each thread can only access the value that it sets by calling the set () method of threadlocal. Even if two different threads have different values set on the same Threadlocal object, they still cannot access the value of the other.

How to access the threadlocal variable

Once you have created a threadlocal variable, you can set a value that you want to save with the following code:

myThreadLocal.set("A thread local value”);

The values stored in the threadlocal variable can be read in the following ways:

String threadLocalValue = (String) myThreadLocal.get();

The Get () method returns an object, and the set () object needs to pass in a parameter of type object.
Specifying a generic type for threadlocal

We can create a Threadlocal object that specifies a generic type, so that we do not need to force type conversions every time the value returned by using the Get () method is used. The following shows an example of the threadlocal for a specified generic type:

private ThreadLocal myThreadLocal = new ThreadLocal<String>();

Now we can only put the string type value into the Threadlocal object.

And we don't need to force the type conversion when we get the value from the threadlocal.

How to initialize the value of a threadlocal variable

Because the value set in the Threadlocal object can only be accessed by a thread that sets this value, the thread cannot use the set () method on the Threadlocal object to hold an initial value, and the initial value can be accessed by all threads.

But we can specify an initial value for a Threadlocal object by creating a threadlocal subclass and overriding the InitialValue () method. As shown in the following code:

private ThreadLocal myThreadLocal = new ThreadLocal<String>() {    @Override    protected String initialValue() {        return "This is the initial value";    }    };

The example above creates a myrunnable instance and passes the instance as a parameter to two threads. Each of the two threads executes the run () method, and each holds a different value on the threadlocal instance. If they are not accessing the Threadlocal object and the called Set () method is synchronized, the second thread overrides the value set by the first thread. However, because they are accessing a Threadlocal object, none of the two threads can see the value saved by the other. That is, they have access to two different values.
About Inheritablethreadlocal

The Inheritablethreadlocal class is a subclass of the Threadlocal class. Each thread in threadlocal has its own value, and unlike Threadlocal, Inheritablethreadlocal allows a thread and all child threads created by that thread to access the values it holds.

Know it

Synchronized this kind of thread synchronization mechanism can solve multi-threaded concurrency problem, in this solution, multiple threads access to the same copy of the contents of the variable. To prevent concurrency errors that may occur during multithreaded access. Having to synchronize access to multiple threads means that multiple threads have to access or modify the value of the variable successively, which is a strategy for increasing the access time in exchange for thread security.

The Threadlocal class maintains its own unique copy of the variable for each thread. Each thread has its own independent variable, the competition conditions are completely eliminated, there is no need to synchronize these threads, they can be the maximum CPU scheduling, concurrent execution. And since each thread accesses the variable, it reads and modifies its own unique copy of the variable, and the variable is completely enclosed in each accessed thread, and the concurrency error may be completely eliminated. In contrast to the previous scenario, this is a strategy for exchanging space for thread security.

Consider an example of using threadlocal to implement database connection connection object thread isolation.

  Import java.sql.connection;import Java.sql.drivermanager;import Java.sql.sqlexception;public class ConnectionManager {private static threadlocal<connection> Connectionholder = new Threadlocal<connection> (            {@Override protected Connection InitialValue () {Connection conn = null; try {conn = drivermanager.getconnection ("Jdbc:mysql://localhost:3306/test", "Usern            Ame "," password ");            } catch (SQLException e) {e.printstacktrace ();        } return conn;    }    };    public static Connection getconnection () {return connectionholder.get ();    } public static void SetConnection (Connection conn) {Connectionholder.set (conn); }}

By calling the Connectionmanager.getconnection () method, each thread gets to the connection object that is bound to the current thread, and when it is first fetched, it is set by the value of the InitialValue () method's return value. The Connection object set through the Connectionmanager.setconnection (Connection conn) method is also bound only to the current thread. This enables complete isolation of the connection object in multiple threads. When managing connection objects in a multithreaded environment in a spring container, the idea is very similar to the code above.

Know the reason why

So how does the Threadlocal class implement this "provide a different copy of the variable for each thread"? Let's take a look at how the source code of the Threadlocal set () method is implemented:

/** * Sets the current thread‘s copy of this thread-local variable * to the specified value.  Most subclasses will have no need to  * override this method, relying solely on the {@link #initialValue} * method to set the values of thread-locals. * * @param value the value to be stored in the current thread‘s copy of *        this thread-local. */public void set(T value) {    Thread t = Thread.currentThread();    ThreadLocalMap map = getMap(t);    if (map != null)        map.set(this, value);    else        createMap(t, value);}

There is no magic, inside this method we see that we first get a threadlocalmap related to the current thread through the Getmap (thread T) method, and then set the value of the variable to this Threadlocalmap object, Of course, if the obtained Threadlocalmap object is empty, it is created by the Createmap method.

The secret of thread isolation lies in the Threadlocalmap class. Threadlocalmap is a static inner class of the Threadlocal class that implements the setting and acquisition of key-value pairs (as compared to the map object), each of which has a separate threadlocalmap copy that stores values that can only be read and modified by the current thread. The Threadlocal class implements the isolation of variable access in different threads by manipulating a threadlocalmap copy of each line thread. Because the variables are unique to each thread, there is no concurrency error at all. Another thing is that the key in the Threadlocalmap stored key-value pair is the Threadlocal object that the this object points to, and the value is the object you set.

To deepen our understanding, let's look at the implementation of the Getmap and Createmap methods that appear in the code above:

ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }

The code has been very straightforward to get and set a variable called threadlocals within the thread, and the type of the variable is threadlocalmap, This further validates the view above: Each thread has its own independent Threadlocalmap object. Open the source code of the Java.lang.Thread class, we can get more visual proof:

/* ThreadLocal values pertaining to this thread. This map is maintained     * by the ThreadLocal class. */    ThreadLocal.ThreadLocalMap threadLocals = null;

Then take a look at the Get () method in the Threadlocal class, which is what the code says:

/** * Returns The value in the current thread's copy of this * thread-local variable. If the variable have no value for the ' current thread ', it is first initialized to the value returned * by an INVOC     Ation of the {@link #initialValue} method. * * @return The current thread's value of this thread-local */public T get () {Thread T = Thread.curren        TThread ();        Threadlocalmap map = getmap (t);            if (map! = null) {Threadlocalmap.entry E = map.getentry (this);        if (E! = null) return (T) E.value;    } return Setinitialvalue (); }/** * Variant of Set () to establish initialvalue.     Used instead * of set () in case user has overridden the set () method.        * * @return The initial value */private T Setinitialvalue () {T value = InitialValue ();        Thread t = Thread.CurrentThread ();        Threadlocalmap map = getmap (t); if (map! = null) Map.set (this, ValUE);        else Createmap (t, value);    return value; }

The code for these two methods tells us that when we get the values that are bound to the current thread, the Threadlocalmap object is looking for the key with the Threadlocal object pointed to by this, which is, of course, echoing the code of the previous set () method.

Further, we can create different threadlocal instances to implement multiple variable access isolation between different threads, why can we do this? Because different threadlocal objects are different keys, you can certainly set different values in the Threadlocalmap object of the thread. By Threadlocal objects, you can share a value and multiple values in multiple threads, just as you would store a key-value pair and multiple key-value pairs in a HashMap object.

Setting the isolation variables in these threads will cause a memory leak? The Threadlocalmap object is stored in the thread object, and when a thread terminates, the thread-isolated variable stored in it is also recycled as the garbage of the thread instance, so there is no need to worry about a memory leak at all. Isolate variables in multiple threads, glorious life, reasonable death, it's perfect, isn't it?

Finally, this isolation strategy for threadlocal variables is not available under any circumstances. If more than one thread of concurrent access to an object instance is allowed, only one can be created, then there is no other way, honestly use the synchronization mechanism to access it.

(11) Join ()

If a thread a executes the thread.join () statement, it means that the current thread a waits for the thread thread to terminate before the Thread.Join () method returns and continues execution down.

Java Multithreading Basics

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.