The basic concept

Concurrency and parallelism

  1. Concurrency: The occurrence of two or more events at the same time interval. When there are multiple threads in operation, if the system has only one CPU, it can not really carry out more than one thread at the same time, it can only divide the CPU running time into a number of time segments, and then allocate the time segments to each thread execution, in a period of time thread code running, other threads are suspended. This is called Concurrent.
  2. Parallel: Two or more events occurring at the same time. When the system has more than one CPU, the operation of the thread may be non-concurrent. When one CPU executes a thread, another CPU can execute another thread. The two threads do not occupy CPU resources, but can execute simultaneously. This method is called Parallel.

Processes and threads

  1. A program may have multiple processes, and a process consists of multiple threads and shared resources
  2. Process: The basic unit of ownership of resources
  3. Thread: The basic unit of independent dispatch

thread

Create a thread

Thread

  1. Inheriting the Thread class (Thread implements the Runnable interface)
  2. Override the run method
  3. The start() method starts the thread

Runnable

  1. Implement the Runnable interface
  2. Override the run method
  3. New Thread(Runnable target), new Thread(Runnable target,String name)

Multiple Thread instances share a Runnable. These threads have the same run method and can share the same data

But there are thread synchronization issues

public class RunnableTest implements Runnable
{
    private int ticket = 10;
    public void run(a)
    {
        while (true)
        {
            if (ticket > 0)
            {
                System.out.println(Thread.currentThread().getName() + "Sold" + ticket + "Ticket number");
                ticket--;
            }
            else System.exit(0); }}public static void main(String[] args)
    {
        RunnableTest rt = new RunnableTest();
        Thread t1 = new Thread(rt, "Window 1");
        Thread t2 = new Thread(rt, "Window 2"); t1.start(); t2.start(); }}Copy the code

print

1Sold at window No.10Ticket number1Sold at window No.9Ticket number1Sold at window No.8Ticket number1Sold at window No.7Ticket number2Sold at window No.7Ticket number2Sold at window No.5Ticket number1Sold at window No.6Ticket number2Sold at window No.4Ticket number1Sold at window No.3Ticket number2Sold at window No.2Ticket number1Sold at window No.1Ticket numberCopy the code

An anonymous class

Anonymous classes can easily access local variables of a method, but must be declared final because the life cycle of anonymous classes is different from that of ordinary local variables

In JDK7, there is no longer a need to display declarations as final, and they are actually declared implicitly by the virtual machine

public static void main(String[] args)
{
    new Thread( )
    {
        public void run( )
        {
            / / content
        }
    }.start( );
    new Thread(new Runnable( )
    {
        public void run( )
        {
            / / content
        }
	}).start( );
}
Copy the code

Callable

  1. Create the Callable implementation class and write the Call () method, which is the thread body and has a return value

  2. Create an instance of the Callable implementation class and wrap the Callable object with a FutuerTask class that encapsulates the return value of the Callable object’s Call () method

  3. Instantiate the FutuerTask class with the object of the FutuerTask interface implementation class to start the thread

  4. The return value of the thread is obtained through the get() method of the object of the FutuerTask class

    public class CallableTest implements Callable<Integer>
    {
        // Override call()
        public Integer call( ) throws Exception
        {
            int i = 0;
            for (; i < 10; i++)
            {
               //
            }
            return i;
        }
        public static void main(String[] args)
        {
            Callable call = new CallableTest( );
            FutureTask<Integer> f = new FutureTask<Integer>(call);
            Thread t = new Thread(f);
            t.start( );
            // Get the return value
            try
            {
                System.out.println("Return value :" + f.get( ));
            }
            catch(Exception e) { e.printStackTrace( ); }}}Copy the code

    print

    The return value:10
    Copy the code

Thread method

  1. Thread body: run()

  2. Start thread: start()

  3. The Thread class method

    methods describe
    public final void setName(String name) Changing the thread name
    public final void setPriority(int priority) Setting the Priority
    public final void setDaemon(boolean on) Set to daemon thread, which terminates automatically when only daemon threads remain
    public final boolean isAlive() Tests whether the thread is active
    public static void yield() Pause the current thread (back to ready state)
    public static void sleep(long millisec) Go into hibernation
    public final void join() Suspends the current thread and waits for the thread calling the method to complete
    public final void join(long millisec) Suspends the current thread for the specified time
    public static Thread currentThread() Returns a reference to the thread object currently executing

Thread state

  1. Ready state:

    • The start() method enters the ready state, waiting for the virtual machine to schedule
    • The run state calls the yield method into the ready state
    • The thread in the LOCK pool acquires the lock and enters the ready state
  2. Run state: Ready state to run state by thread scheduling

  3. Blocking state:

    • Sleep: Call the sleep method
    • Object WAIT pool: call wait or Join and enter the lock pool after notify
    • Object Lock pool: No lock was acquired
  4. Dead: The run method is complete

    Graph TB T (new thread) - start method -- > A (ready state) - A thread scheduling - > B (running) B - yield method -- > A to B - sleep - > D (block: sleep) B - wait or join method -- > E (blocking: wait pool) B - not for lock - > F (block: lock pool) B - run method performed - > C (death) D - time to -- -- > A E - notify method -- -- > F F - gets the lock > A

Thread synchronization

The process of ensuring atomicity, visibility, and orderliness of programs

Non-blocking synchronous

Pessimistic concurrency strategy based on lock contention

synchronized

  1. Synchronized meaning

    • Synchronized locks an object, and when other threads want to lock the object to execute some code, they must wait for the thread that already holds the lock to release the lock

    • The lock is released by mutex code execution, an exception is thrown, and the lock object calls the WAIT method

  2. Different usage methods represent different lock granularity

    • Synchronized (this)
    • Static methods = synchronized(x.class)
    • Decorates a code block (Object extends Object)

ReentrantLock

  1. Create the Lock Lock

    ReentrantLock implements Lock interface, Lock Lock = new ReentrantLock()

  2. The Lock meaning

    • Use the lock() method to indicate that the current thread owns the lock object

    • To release an object, use unlock(), usually ina finally block

  3. Trylock method

    • Synchronized waits forever for a Lock, while Lock provides a trylock method that attempts to occupy it for a specified amount of time
    • With trylock, determine when releasing the lock. If the capture fails, unlock throws an exception
  4. Lock thread interaction

    • Condition Condition = lock.newcondition ()

    • Call the Condition’s: await, signal, signalAll methods

  5. The sample

    public class LockTest
    {
        public static void log(String msg)// Log method
        {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = new Date( );
            String dateStr = sdf.format(date);
            System.out.println(dateStr + "" + Thread.currentThread( ).getName( ) + "" + msg);
        }
        public static void main(String[] args)
        {
            Lock lock = new ReentrantLock( );
            new Thread("t1")
            {
                public void run( )
                {
                    boolean flag = false;
                    try
                    {
                        log("Thread started");
                        log("Try to hold lock");
                        flag = lock.tryLock(1, TimeUnit.SECONDS);
                        if (flag)
                        {
                            log("Successfully occupied lock");
                            log("Perform a 3-second service operation");
                            Thread.sleep(3000);
                        }
                        else
                        {
                            log("Possession lock failed after 1 second attempt, possession abandoned"); }}catch (InterruptedException e)
                    {
                        e.printStackTrace( );
                    }
                    finally
                    {
                        if (flag)
                        {
                            log("Release the lock");
                            lock.unlock( );
                        }
                    }
                    log("Thread terminated");
                }
            }.start( );
            try
            {
                // let t1 run for two seconds first
                Thread.sleep(2000);
            }
            catch (InterruptedException e1)
            {
                e1.printStackTrace( );
            }
            new Thread("t2")
            {
                public void run( )
                {
                    boolean flag = false;
                    try
                    {
                        log("Thread start");
                        log("Try to hold lock");
    
                        flag = lock.tryLock(1, TimeUnit.SECONDS);
                        if (flag)
                        {
                            log("Successfully occupied lock");
                            log("Perform a 3-second business operation");
                            Thread.sleep(3000);
                        }
                        else
                        {
                            log("Possession lock failed after 1 second attempt, possession abandoned"); }}catch (InterruptedException e)
                    {
                        e.printStackTrace( );
                    }
                    finally
                    {
                        if (flag)
                        {
                            log("Release the lock");
                            lock.unlock( );
                        }
                    }
                    log("Thread terminated"); } }.start( ); }}Copy the code

    print

    2019-11-07 15:50:01The T1 thread has been started2019-11-07 15:50:01T1 attempts to hold the lock2019-11-07 15:50:01T1 successfully held the lock2019-11-07 15:50:01T1 to perform3Second service Operation2019-11-07 15:50:03T2 thread start2019-11-07 15:50:03T2 attempts to possess the lock2019-11-07 15:50:04T2 after1Second attempt, possession lock failed, surrender possession2019-11-07 15:50:04End of t2 thread2019-11-07 15:50:04T1 to release the lock2019-11-07 15:50:04End of t1 threadCopy the code
  6. Synchronized is different from Lock

    • Synchronized is the keyword, Lock is the interface, synchronized is the built-in language implementation, Lock is the code level implementation
    • Synchronized automatically releases the Lock after it is executed. Lock displays unlock().
    • Synchronized waits and tries to occupy the Lock. Lock can use trylock to attempt to occupy the Lock within a certain period of time. When the Lock fails to occupy the Lock, it is abandoned

Nonblocking synchronization

Non-blocking synchronization is an optimistic concurrency strategy based on conflict detection and data update

Actomic class

  1. Atomic operation

    • Atomic operations are non-interruptible operations that must be performed at once
    • Assignment is an atomic operation, but a++ is not an atomic operation, but three steps: evaluate, add one, and assign
    • One thread takes the value of I, and before it can increment by one, the second thread takes the value of I, which is a thread-safety problem
  2. Use of actomic classes

    • Jdk6 has later, the new package Java. Util. Concurrent. Atomic, there are all kinds of atomic classes, such as AtomicInteger
    • AtomicInteger provides a variety of increment, decrement, and other methods that are atomic. In other words, the increment method incrementAndGet is thread-safe
    • 10000 threads doing value plus one, using a++ method to get inaccurate result, using AtomicInteger addAndGet() method to get correct result
    public class ThreadTest{    static int value1 = 0;    static AtomicInteger value2 = new AtomicInteger(0);Public static void main(String[] args) {for (int I = 0; i < 100000; i++) { new Thread( ) { public void run( ) { value1++; } }.start( ); new Thread( ) { public void run( ) { value2.addAndGet(1); //value++ atomic operation}}.start(); } while (Thread.activeCount( ) > 2) { Thread.yield( ); } System.out.println(value1); System.out.println(value2); }}
    Copy the code

    print

    99996100000
    Copy the code

Asynchronous scheme

If a method does not involve sharing data, it is inherently thread-safe

Reentrant code

Code can be interrupted at any point in its execution, and another piece of code can be executed, without any errors in the original program after control is returned

  1. A method that returns predictable results and returns the same results with the same input data is reentrant, which means thread-safe

  2. Stack closure is reusable code

    There is no thread-safety issue when multiple threads access a local variable of the same method, because local variables are stored in the virtual machine stack, in the thread’s private area, so there is no thread-safety issue

    public class ThreadTest{    static void add( )    {        int value = 0;        for (int i = 0; i < 1000; i++)        {            value++;        }        System.out.println(value);    }    public static void main(String[] args)    {        ExecutorService threadPool = Executors.newCachedThreadPool( );        threadPool.execute(( ) -> add( ));        threadPool.execute(( ) -> add( ));        threadPool.shutdown( );    }}
    Copy the code

    print

    10001000
    Copy the code

Thread local storage

  1. Limiting the visibility of shared data to the same thread can avoid data contention even without synchronization

  2. Use the java.lang.ThreadLocal class to implement thread-local storage

    • A ThreadLocal variable is a variable that different threads can have different values, and all threads can share a ThreadLocal object
    • A change in the ThreadLocal value of one thread does not affect other threads
    • Assign and view ThreadLocal variables using the set() and get() methods
    public class ThreadLocalDemo{    public static void main(String[] args)    {        ThreadLocal threadLocal1 = new ThreadLocal( );        Thread t1 = new Thread(( ) ->        {            threadLocal1.set(1);            try            {                Thread.sleep(3000);            }            catch (InterruptedException e)            {                e.printStackTrace( );            }            System.out.println(threadLocal1.get( ));        });        Thread t2 = new Thread(( ) -> threadLocal1.set(2));        t1.start( );        t2.start( );    }}
    Copy the code

    print

    1
    Copy the code
  3. ThreadLocal principle

    • Each thread has a ThreadLocal ThreadLocalMap object, call threadLocal1. The set value (T) method, the threadLoacl1 and the value of key-value pairs in the map
    • The underlying data structure of ThreadLocalMap can cause memory leaks. If possible, call the remove() method after using ThreadLocal

A deadlock

A deadlock condition

  1. Mutual exclusion conditions
  2. Request and hold conditions
  3. Inalienable condition
  4. Cyclic waiting condition (loop condition)

Java deadlock example

public static void main(String[] args){    Object o1 = new Object( );    Object o2 = new Object( );    Thread t1 = new Thread( )    {        public void run( )        {            synchronized (o1)Println ("t1 already owns o1 "); // hold o1 {system.out.println ("t1 already owns o1 "); try { Thread.sleep(1000); O1} Catch (InterruptedException e) {e.printStackTrace(); } system.out. println(" T1 tries to occupy O2 "); System.out.println("t1 waiting "); Synchronized (O2) {system.out.println ("t1 has occupied O2"); }}}}; Thread t2 = new Thread() {public void run() {synchronized (o2) {system.out.println ("t2 "); try { Thread.sleep(1000); O2} Catch (InterruptedException e) {e.printStackTrace(); } system.out. println("t2 attempts to occupy o1"); System.out.println("t2 waiting "); Synchronized (o1) {system.out.println ("t2 "); synchronized (o1) {system.out.println ("t2 "); }}}}; t1.start( ); t2.start( ); }
Copy the code

print

T1 is in possession O1t2 is in possession o2T1 is trying to occupy O2T1 in waiting T2 is trying to occupy O1t2 in waitingCopy the code

Thread communication

  1. Object class method

    methods describe
    wait() The thread enters the wait pool
    notify() Wakes up the thread waiting for the current thread lock
    notifyAll() Wake up all threads, with higher priority

    Why are these methods set on Object objects?

    Superficially, because any object can be locked

    Each Object is set with a data structure similar to a collection, which stores the thread that has acquired the lock, the thread that is waiting to acquire the lock, and the thread that is waiting to be awakened.

  2. Producer-consumer model

    • The sleep method yields the CPU, but does not drop the lock
    • The wait method enters the wait pool of the lock object and drops the lock
public class ProducerAndConsumer{    public static void main(String[] args)    {        Goods goods = new Goods();        Thread producer = new Thread()Public void run() {while (true) goods.put(); }}; Public void run() {while (true) goods.take(); }}; consumer.start(); producer.start(); }}class Goods {int num = 0; Int space = 10; Public synchronized void put() {if (num < space) {num++; System.out.println(" insert item, existing "+ num +" item, "+ (space-num) +" space "); notify(); } else {try {system.out.println (" there is no place to put, waiting for "); wait(); // Enter the wait pool for the lock object} catch (InterruptedException e) {e.printStackTrace(); }}} public synchronized void take() {if (num > 0); System.out.println(" select an item, existing "+ num +" item, "+ (space-num) +" space "); notify(); } else {try {system.out.println (" No item available, waiting to be placed "); wait(); // Enter the wait pool for the lock object} catch (InterruptedException e) {e.printStackTrace(); }}}}
Copy the code

print

No goods to take, waiting to be put into put into an item, available1A commodity,9One slot into an existing item2A commodity,8A vacancy takes out an item that is available1A commodity,9One slot into an existing item2A commodity,8One slot into an existing item3A commodity,7One slot into an existing item4A commodity,6A vacancy takes out an item that is available3A commodity,7One slot into an existing item4A commodity,6A vacancy...Copy the code

The thread pool

Starting and ending threads are time consuming and resource consuming, and if you use a lot of threads in your system, a lot of starting and ending actions can seriously affect performance

Thread pooling is much like the producer-consumer model, where the objects consumed are individual, runnable tasks

  1. Design ideas

    • Prepare a task container, which can be used as a List to store tasks
    • Create multiple actor threads in the thread pool class constructor
    • When the task container is empty, all threads wait
    • When an external thread adds a task to the task container, a performer thread is notified
    • After the execution of the task, no new task is received, it returns to the waiting state
  2. Implement a thread pool

    public class ThreadPool{    int poolSize;New LinkedList
            
              tasks = new LinkedList
             
              (); Public ThreadPool(int poolSize) {this.poolSize = poolSize; Synchronized (tasks)// start poolSize {for (int I = 0; i < poolSize; I ++) {new ExecuteThread(" ExecuteThread "+ I).start(); }}} public void add(Runnable r) {synchronized (tasks) {tasks.add(r); System.out.println(" Add new task "); tasks.notifyAll(); }} class ExecuteThread extends Thread {Runnable task; public ExecuteThread(String name) { super(name); } public void run() {system.out.println (" start: "+ this.getName()); while (true) { synchronized (tasks) { while (tasks.isEmpty()) { try { tasks.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } task = tasks.removeLast(); tasks.notifyAll(); } system.out.println (this.getName() + "Received ");} system.out.println (this.getName() +" received "); task.run(); }} public static void main(String[] args) {ThreadPool pool = new ThreadPool(3); for (int i = 0; i < 5; I++) {Runnable task = new Runnable() {public void run()// task content { System.out.println(thread.currentThread ().getName()+" Execute task "); }}; pool.add(task); // Add task try {thread.sleep (1000); } catch (InterruptedException e) { e.printStackTrace(); }}}}
             
            
    Copy the code

    print

    Main added a new task start: the executor thread0Executor thread0Receive the task executor thread0Execution task initiation: executor thread1Start: Performer thread 2main adds a new task-performer thread2Receive the task executor thread2Main adds a new thread of task implementer2Receive the task executor thread2Perform a taskCopy the code
  3. Java thread pool class

    • The default thread pool class, ThreadPoolExecutor, is under the java.util.concurrent package

      ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10.15.60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());/* The first argument is of type int, 10 indicates that the pool is initialized with 10 threads working in it. The second argument is of type int, 15 indicates that if 10 threads are insufficient, Timeununit. SECONDS (60) and timeunit. SECONDS (4) indicate that after 60 SECONDS, the additional threads will not receive the task and will be recycled. Finally, there are 10 fifth BlockingQueue parameters in the pool. New LinkedBlockingQueue() is used to hold the collection of tasks */
      Copy the code
    • The execute() method adds a new task

      public class TestThread {       public static void main(String[] args) throws InterruptedException     {        ThreadPoolExecutor threadPool= new ThreadPoolExecutor(10.15.60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());        threadPool.execute(new Runnable()        {Public void run() {system.out.println (" Execute task "); }}); }}
      Copy the code
  4. Several thread pools in Java

    The top-level interface of Java thread pools is Executor, and the ExecutorService subinterface is more widely used

    The Executors class provides a series of factory methods for creating thread pools that implement the ExecutorService interface

    • NewCachedThreadPool A buffered thread pool, the number of threads controlled by the JVM, and no new threads are created when threads are available
    • NewFixedThreadPool, fixed size thread pool. When the number of tasks exceeds the number of threads, the tasks are queued
    • NewScheduledThreadPool, which creates a thread pool that can schedule commands to run after a given delay or to execute them periodically
    • NewSingleThreadExecutor, a single thread that executes multiple tasks sequentially and creates a new one if it terminates unexpectedly
    ExecutorService threadPool = null; threadPool = Executors.newCachedThreadPool();/ / buffer pool threadPool = Executors. NewFixedThreadPool (3); / / fixed-size pool threadPool = Executors. NewScheduledThreadPool (2); / / timing task thread pool threadPool = Executors. NewSingleThreadExecutor (); ThreadPool = new ThreadPoolExecutor(···); // Default thread pool, multiple controllable parameters
    Copy the code

Thread-safe classes

  1. StringBuffer: Internal methods modified with synchronized
  2. Vetort: inherits from AbstractList
  3. Stack: inherits from Vector
  4. HashTable: inherits from Dictionary and implements Map interface
  5. Property: extends from HashTable and implements the Map interface
  6. ConcurrentHashMap: segment locking mechanism