What is thread, process, multithreading
Process: a game, a video software, a QQ. Process is the process of program execution
Thread: the picture and sound of the game. Thread is the unit of CPU scheduling and execution
A process contains at least one thread
thread
The difference between thread and process
- Address space: threads share the address space of the process, and processes have independent address space.
- Resources: threads share the resources of the process, such as memory, I/O, cpu, etc., which is not conducive to the management and protection of resources, while the resources between processes are independent and can be well managed and protected.
- Robustness: multi process is more robust than multi thread. After a process crashes, it will not affect other processes in protected mode, but a thread crashes and the whole process dies.
- Execution process: each independent process has an entry for program operation, sequential execution sequence and program entry, which costs a lot of execution. However, threads cannot be executed independently. They must be stored in the application program. The application program provides multiple thread execution control, and the execution overhead is small.
- Concurrency: both can be executed concurrently.
- Switching: process switching consumes large resources and has high efficiency. Therefore, when it comes to frequent switching, using threads is better than processes. Similarly, if concurrent operations that require simultaneous and shared variables are required, only threads can be used, not processes.
- Others: threads are the basic unit of processor scheduling, but processes are not.
Create thread
Thread class - inherit thread class key points
Runable interface - key points of implementing runable interface
Callable interface - Implementation of callable interface
public class Thread01 extends Thread { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println("This is a test"); } } public static void main(String[] args) { // Instantiate a class containing multiple threads and start the thread with the start() method Thread01 thread01 = new Thread01(); thread01.start(); for (int i = 0; i < 500; i++) { System.out.println("Insert value"); } } }
Operation results:
Runnable interface
The runnable interface can also implement multithreading
The runnable interface is a static proxy class
It is recommended to use the runnable interface to avoid the limitation of single inheritance and facilitate the use of the same object by multiple threads
public class Thread03 implements Runnable{ @Override public void run() { for (int i = 0; i < 200; i++) { System.out.println("case:"+i); } } //runnable uses a static proxy public static void main(String[] args) { //Create thread Thread03 thread03 = new Thread03(); //Instantiate the thread body and import the runnable target new Thread(thread03).start(); for (int i = 0; i < 100; i++) { System.out.println("test:"+i); } } }
Concurrent
Acquaintance concurrency
/** * Single object, multiple threads * Train ticket simulation, problem: multithreading. If there are too many threads, it may lead to high concurrency. Different people grab the same ticket */ public class Thread04 implements Runnable{ private int ticket = 10; @Override public void run() { while (ticket > 0) { System.out.println(Thread.currentThread().getName() + "->Got the second" + ticket-- + "Ticket"); } } public static void main(String[] args) { Thread04 thread04 = new Thread04(); new Thread(thread04,"Small 1").start(); new Thread(thread04,"Small 3").start(); new Thread(thread04,"Small 2").start(); } }
Tortoise and rabbit race
The runnable interface is used to compare who gets to the destination first among multiple threads of an object
/** * Multi thread tortoise rabbit race */ public class Race implements Runnable{ // winner private static String winner; // Thread body @Override public void run() { for (int i = 0; i <= 101; i++) { //Judge whether the game is over boolean flag = gameOver(i); if (flag){ break; } System.out.println(Thread.currentThread().getName()+"Run away"+i+"step"); } } private boolean gameOver(int steps){ if (winner!=null){ return true; }else { if (steps>=101){ winner = Thread.currentThread().getName(); System.out.println("winner is "+winner); return true; } } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race,"rabbit").start(); new Thread(race,"tortoise").start(); } }
Thread state
Thread stop
It is not recommended to use the obsolete stop(), destroy() provided by JDK for thread stop
Stop the thread and create an identifier to stop the thread, which is safer
The identifier flag=false indicates that the thread stops running
//Thread stopped, identifier public class ThreadStop implements Runnable{ //Set identification bit private Boolean flag = true; @Override public void run() { int i=0; while (flag){ System.out.println("Thread stop"+i++); } } public static void main(String[] args) { ThreadStop threadStop = new ThreadStop(); new Thread(threadStop).start(); for (int i = 0; i < 100; i++) { if (i>50){ threadStop.isStop(); } System.out.println(i); } } //Change identification bit public void isStop() { this.flag=false; } }
Thread delay sleep
Thread delay can be set using Thread.sleep
The thread needs to throw an exception InterruptedException
When sleep arrives, it enters the ready state
sleep can be used to simulate network delay, countdown, etc
Each object has a lock, and sleep does not release the lock
import java.text.SimpleDateFormat; import java.util.Date; //Simulate real-time acquisition of current time public class ThreadSleep01 { public static void main(String[] args) { //Get current time Date date = new Date(System.currentTimeMillis()); while (true){ try { //Thread delay Thread.sleep(1000); //Update time date = new Date(System.currentTimeMillis()); //Format time System.out.println(new SimpleDateFormat("yyyy:HH:dd HH:mm:ss").format(date)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Thread yield
advantage:
-
Comity thread, which suspends the currently executing thread without blocking
-
Transition a thread from a running state to a ready state
-
Let the cpu reschedule. Comity may not be successful. It depends on the cpu mood
//Thread comity, comity does not necessarily succeed public class ThreadYield implements Runnable{ public static void main(String[] args) { ThreadYield threadYield = new ThreadYield(); new Thread(threadYield,"Xiaobai").start(); new Thread(threadYield,"Xiao Ming").start(); new Thread(threadYield,"Xiao Hei").start(); } @Override public void run() { System.out.println(Thread.currentThread().getName()+"Execution thread"); Thread.yield(); //Open comity System.out.println(Thread.currentThread().getName()+"Close thread"); } }
Comity success chart:
Comity failure diagram:
Thread queue join
join is not recommended, which will cause thread blocking
Multithreading is executed synchronously. When Thread.join() is used, Thread.run() will be executed before other threads are executed
//join queue jumping analysis public class ThreadJoin implements Runnable{ @Override public void run() { //run thread for (int i = 0; i < 200; i++) { System.out.println("Queue jumper->>>>>"+i); } } public static void main(String[] args) { ThreadJoin threadJoin = new ThreadJoin(); //Static proxy import object Thread thread = new Thread(threadJoin); //Turn on Multithreading thread.start(); //Create a main thread for (int i = 0; i < 100; i++) { System.out.println("People in line->"+i); if (i==50){ try { //Start queue jumping and execute the run thread thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
Thread state
Thread status. A thread can be in one of the following states:
- NEW
Threads that have not been started are in this state. - RUNNABLE
The thread executing in the Java virtual machine is in this state. - BLOCKED
Threads that are blocked waiting for a monitor lock are in this state. - WAITING
A thread that is waiting for another thread to perform a specific action is in this state. - TIMED_WAITING
The thread that is waiting for another thread to perform the action for the specified waiting time is in this state. - TERMINATED
The exited thread is in this state.
Thread lifecycle:
New - > runnable - > timed_ Blocking - > terminated
Full code:
public class ThreadState{ public static void main(String[] args) { //Using lambda expressions to execute the runnable interface Thread thread = new Thread(()->{ //Loop 5 threads for (int i = 0; i < 5; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("End of thread execution"); }); //Gets the status of the thread Thread.State state = thread.getState(); //Input thread status System.out.println(state); //Start thread NEW thread.start(); //Loop output thread current state while (state != Thread.State.TERMINATED){ try { Thread.sleep(100); state = thread.getState(); System.out.println(state); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Thread priority
Low thread priority only means that the probability is reduced, not from low to high. It depends on the cpu scheduling
Priority range of thread: 1 ~ 10
- Thread.MIN_PRIORITY=1;
- Thread.MAX_PRIORITY=10;
- Thtead.NORM_PRIORITY=5;
Change priority:
- getPriority().setPriority(int xx)
Full code:
//Get and set thread priority public class ThreadPriority { public static void main(String[] args) { //Gets the priority of the main thread. The priority of the main function is 5 by default System.out.println(Thread.currentThread().getName() + "->>" + Thread.currentThread().getPriority()); MyThread myThread = new MyThread(); //Creating multithreaded objects Thread thread1 = new Thread(myThread); Thread thread2 = new Thread(myThread); Thread thread3 = new Thread(myThread); Thread thread4 = new Thread(myThread); //Set the thread priority and start the thread thread1.setPriority(9); thread1.start(); thread2.setPriority(1); thread2.start(); thread3.setPriority(5); thread3.start(); thread4.setPriority(3); thread4.start(); } } class MyThread implements Runnable{ @Override public void run() { //Outputs the priority of all created threads System.out.println(Thread.currentThread().getName() + "->>" + Thread.currentThread().getPriority()); } }
Thread daemon
Daemon thread:
- Threads are divided into user threads and daemon threads
- The virtual machine must ensure that the user thread has completed execution
- The virtual machine does not have to wait for the daemon thread to complete execution, such as background operation log, monitoring memory and GC recovery
Full code:
//Turn on protected thread public class ThreadDaemon implements Runnable{ public static void main(String[] args) { //Open main thread new Thread(new ThreadDaemon()).start(); Thread threadGod = new Thread(new God()); //Modify user process as protection process threadGod.setDaemon(true); // The default value is false, which means that the user often, and changed to true to protect the process threadGod.start(); //Open human thread new Thread(new Man()).start(); } @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println("->>>>>"+i); } } } class God implements Runnable{ @Override public void run() { while (true){ System.out.println("God protects you"); } } } class Man implements Runnable{ @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println("You're through->"+i+"day"); } } }
Thread synchronization
Conditions for thread synchronization: queue + lock
Thread synchronization is like several people going to a toilet together. Locking is equivalent to a door. If you lock it, others can't get in. It has strong security and low efficiency
Although it is convenient for multiple threads brought by a process to share a piece of storage space, it will cause conflict. In order to ensure the correctness of data access in the method, the lock mechanism synchronized is added during access. When one thread obtains the exclusive lock of the object and monopolizes resources, other threads must wait and release the lock after use. There are some problems:
- Holding a lock by one thread will cause all other threads that need the lock to hang
- In multi-threaded competition, locking and releasing locks will lead to context switching and scheduling delay, resulting in performance problems
- If a high priority thread waits for a low priority thread to release the lock, it will lead to priority inversion and performance problems
Unsafe thread instance:
//Unsafe ticket grabbing multithreading public class ThreadSafety{ public static void main(String[] args) { Buy buy = new Buy(); new Thread(buy,"First person").start(); new Thread(buy,"The second person").start(); new Thread(buy,"The third person").start(); } } class Buy implements Runnable{ private int tickNumber = 10; boolean flag = true; @Override public void run() { while (true){ isBuy(); } } public void isBuy(){ if (tickNumber<0){ flag=false; return; } System.out.println(Thread.currentThread().getName()+"Got it"+tickNumber--); } }
Result diagram:
Thread safety
synchronized
Synchronization method:
synchronized method:
public synchronized void medhod(int agrs){}
synchronized block:
synchronized (What to lock){}
Add synchronized methods and methods to complete synchronization
Synchronized methods control access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object, otherwise the thread will block. Once the method is executed, it monopolizes the lock. The lock is not released until the method is put back. The blocked thread can obtain the lock and continue to execute
Methods are divided into read-only and modified methods. We only need to synchronize the modified methods
The synchronized method locks this by default
The synchronizad block can lock any object
Complete code of synchronizad method:
package com.hdt.kuangshen.thread; //Thread delay public class ThreadSleep implements Runnable{ //Set the number of votes private static int piao =10; @Override public synchronized void run() { while (piao > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "->" + piao-- + "ticket"); } } public static void main(String[] args) { ThreadSleep threadSleep = new ThreadSleep(); new Thread(threadSleep,"Xiao Ming").start(); new Thread(threadSleep,"Xiaobai").start(); new Thread(threadSleep,"Xiao Hei").start(); } }
synchronizad block complete code:
import java.util.ArrayList; import java.util.List; public class ThreadSafety01 { public static void main(String[] args) { List<String> list = new ArrayList<>(); for (int i = 0; i <= 10000; i++) { new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(list.size()); } }
CopyOnWriteArrayList (understand)
A collection of test juc security classes
Full code:
//A collection of test juc security classes public class ThreadCopyOnWriteArraylist { public static void main(String[] args) { //Create security collection CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 1000; i++) { new Thread(()->{ //Add to juc security collection list.add(Thread.currentThread().getName()); }).start(); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(list.size()); } }
deadlock
What is deadlock:
Deadlock refers to the blocking caused by competing resources or communicating with each other during the execution of two or more processes. Without external force, it will not continue
Four important conditions for deadlock generation:
- Mutex condition: a resource can only be used by one process at a time.
- Request and hold condition: when a process is blocked by requesting resources, it will hold on to the obtained resources.
- Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived until they are used up at the end of the year.
- Circular waiting condition: a circular waiting resource relationship is formed between several processes.
Full code:
//Thread lock public class ThreadDieLock { public static void main(String[] args) { Lock lock1 = new Lock(0,"First person"); Lock lock2 = new Lock(2,"Second person"); new Thread(lock1).start(); new Thread(lock2).start(); } } //pen class Pen{} //Pen cover class Cover{} //Lock grab class Lock implements Runnable{ static Pen pen = new Pen(); static Cover cover = new Cover(); int choice; String pName; Lock(int choice,String pName){ this.choice=choice; this.pName=pName; } @Override public void run() { try { Grab(); } catch (InterruptedException e) { e.printStackTrace(); } } //Cause locking public void Grab() throws InterruptedException { if (choice==0){ synchronized (pen){ System.out.println(this.pName+"Want a pen"); Thread.sleep(1000); synchronized (cover){ System.out.println(this.pName+"To cover"); } } }else { synchronized (cover){ System.out.println(this.pName+"To cover"); Thread.sleep(1000); synchronized (pen){ System.out.println(this.pName+"Want a pen"); } } } } }
Lock lock
Reentrant lock, which realizes synchronization by explicitly defining the synchronization lock object, starting from jdk5.0
ReentrantLock implements Lock. Like synchronized, ReentrantLock is commonly used
example:
class A{ private final ReentrantLock lock = new ReentrantLock(); public void b(){ lock.lock(); try { //Code that needs to protect safe threads }finally { lock.unlock(); //If there are exceptions in the synchronization code, write unlock() to finally } } }
Full code:
import java.util.concurrent.locks.ReentrantLock; //Use of thread locks public class ThreadLock { public static void main(String[] args) { LockTest lockTest = new LockTest(); //Define multiple resources to get the same object new Thread(lockTest).start(); new Thread(lockTest).start(); new Thread(lockTest).start(); } } class LockTest implements Runnable{ private int ticket = 10; //Lock class private final ReentrantLock reentrantLock = new ReentrantLock(); @Override public void run() { try { grab(); } catch (InterruptedException e) { e.printStackTrace(); } } public void grab() throws InterruptedException { //When starting the lock, it is best to add try{}finally {close the lock} reentrantLock.lock(); try { while (ticket>0){ Thread.sleep(1000); System.out.println(ticket--); } }finally { //Unlock reentrantLock.unlock(); } } }
Comparison between Lock and synchronized:
- Lock is a display lock (manually opening and closing the lock), and synchronized is an implicit lock (automatically released when out of scope)
- Lock only has code block lock, and synchronized has code block lock and method lock
- Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better extensibility (providing more subclasses)
- Priority:
- Lock > synchronize code block (it has entered the method body and allocated corresponding resources) > synchronize method (outside the method body)
Producer / consumer issues
- When the buffer is empty, consumers can no longer consume
- When the buffer is full, the producer can no longer produce
- When one thread is producing or consuming, other threads can no longer produce or consume, that is, keep the synchronization between threads
- Note the order of conditional variables and mutexes
Using buffer to solve: pipe pass method
Thread pool
Due to frequent creation and destruction, it has a great impact on performance
solve:
Create multiple threads in advance, put them into the thread pool, get them directly when using them, and put them back into the pool after using them
Benefits:
- Increase the corresponding speed
- Reduce resource consumption
- Easy thread management
- Thread configuration resolution
- int corePoolSize / / number of core threads
- int maximumPoolSize / / maximum number of threads (core threads + temporary threads)
- long keepAliveTime / / maximum idle time of temporary thread
- Timeunit / / time unit (for temporary thread)
- BlockingQueue workQueue / / task queue
- ThreadFactory threadFactory / / thread factory (you can name the thread). The default name of the thread in the thread pool is pool-m-thread-n
- Rejectedexecutionhandler / / reject policy
ExecutorService interface
The ExecutorService interface can be used to manage the thread pool, such as submitting tasks and stopping tasks
Common interfaces of thread pool:
-
void shutdown() destroy the thread pool after all tasks in the task queue have been executed (no new task submission is allowed)
- The running task will not be affected. Continue to run
- The task submitted after shutdown() will throw RejectedExecutionException, which means that it is rejected
-
List < runnable > shutdownnow() (may) stop the executing task, suspend the processing of the waiting task, and return to the list of waiting tasks
- The task submitted after shutdownNow() will throw RejectedExecutionException, which means that it refuses to receive
- For running tasks
- If the code of this task can throw InterruptedException (such as wait, sleep, join method, etc.), stop this task and throw InterruptedException
- If the InterruptedException exception cannot be thrown in the code of this task, the task will continue to run until the end
-
<T> Future < T > submit (callable < T > task) submits a task with a return value and returns a future object representing the task
-
Future<?> Submit (Runnable task) submits a Runnable task and returns a future object representing the task
-
<T> Future < T > submit (Runnable task, t result) submits a Runnable task and returns a future object representing the task
- There is an execute(Runnable task) method in the Executor interface, which can be used to submit Runnable tasks
Get interface instance
- To obtain the ExecutorService instance, you can use the static methods in the Executors class in the JDK. The common methods are as follows
- static ExecutorService newCachedThreadPool() with cached thread pool
- Fixed size thread pool static ExecutorService newFixedThreadPool(int nThreads)
- Single thread pool static ExecutorService newSingleThreadExecutor()
Use cache thread pool
- Usage method ExecutorService executorService = Executors.newCachedThreadPool();
characteristic:
- The number of core threads is 0, all threads are temporary threads, and threads can be reused
- The maximum number of threads is Integer.MAX_VALUE, which represents the largest integer in Java, means that threads can be created indefinitely
- The maximum idle time of temporary thread is 60s
- The way of task queue (blocking queue) is that there is no capacity. A task uses a thread to execute it, and the task will not wait
- It is suitable for the situation where the number of tasks is intensive but the execution time of each task is short
Since each thread will be returned to the pool after execution, and other tasks can be executed in idle time, it is named with cache
Full code:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPool { public static void main(String[] args) { //Set thread pool size ExecutorService service = Executors.newFixedThreadPool(10); service.execute(new MyThreads()); service.execute(new MyThreads()); service.execute(new MyThreads()); service.execute(new MyThreads()); //Close link service.shutdown(); } } class MyThreads implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }