1. Thread overview
1.1 threads and processes
- Process is a program in the running process and has certain independent functions
- Concurrency: only one instruction can be executed at a time, but multiple process instructions are executed in rapid rotation
- Parallelism: multiple instructions are executed simultaneously on multiple processors
- A thread is the execution unit of a process
1.2 advantages of multithreading
- Memory cannot be shared between processes, but it is very easy between threads
- When the system creates a process, it needs to reallocate system resources for the process, but the cost of creating a thread is much less, so using multithreading is more efficient
- The Java language has built-in multithreading
2. Thread creation and startup
2.1 inherit Thread
public class FirstThread extends Thread { private int i; @Override public void run() { for(i = 0; i < 50; i ++){ System.out.println(this.getName() + "" + i); } } public static void main(String[] args){ FirstThread ft = new FirstThread(); for(int i =0; i < 100;i ++){ System.out.println(Thread.currentThread().getName() + "" + i); if(i == 20) { ft.run(); } } } }
2.2 implementation of Runnable interface
public class FirstThread implements java.lang.Runnable { private int i; public void run() { for(i = 0; i < 50; i ++){ System.out.println(Thread.currentThread().getName()+ "" + i); } } public static void main(String[] args){ FirstThread ft = new FirstThread(); for(int i =0; i < 100;i ++){ System.out.println(Thread.currentThread().getName() + "" + i); if(i == 20) { ft.run(); } } } }
2.3 using Callable and Future
- The Callable interface provides a call() method that can be used as the thread execution body. The call() method has a return value and can declare to throw an exception
- Java 5 provides a Future interface to represent the return value of the call() method in the Callable interface, and provides a futureask implementation class for the Future interface
- Methods defined by Future interface:
Method name | effect |
---|---|
boolean cancel(boolean mayInterruptIfRunning) | Attempt to cancel the associated Callable task in the Future |
V get() | Returns the return value of the call method in the Callable task. This method will cause thread blocking and can only be obtained after the sub thread is executed |
V get(long timeout, TimeUnit unit) | Returns the return value of the call method in the Callable task. This method allows the program to block the time specified by timeout and unit at most. If the Callable task has not returned a value after the specified time, a TimeoutException exception will be thrown |
boolean isCancelled() | Cancel the task in Callable |
boolean isDone() | Is the task in Callable completed |
public class CallableDemo { public static void main(String[] args){ FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> { int i = 0; for( ; i < 100; i++){ System.out.println(i); } return i; }); new Thread(task).start(); try { System.out.println(task.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
2.4 comparison of three ways to create threads
Advantages and disadvantages of Runnable and Callable:
- Thread class only implements Runnable and Callable interfaces, and can inherit other classes
- In the case of Runnable and Callable, multiple threads can share the same target object, so it is very suitable for multiple threads to process the same resource
- Programming is slightly more complex, and if you need to access the current thread, you must use Thread.currentThread()
Thread strengths and weaknesses:
- Thread class already inherits thread class, so it cannot inherit other parent classes
- The writing is simple. If you need to access the current thread, use this
3. Thread life cycle
3.1 new and ready status
- The new statement is only allocated memory by the Java virtual machine, and does not show the dynamic characteristics of any thread
- If the run method of the inherited class is called directly, there will only be MainActivity, and the name of the current execution thread cannot be obtained through getName, but Thread.currentThread().getName()
- After calling the run method, the thread is no longer in the new state
3.2 operation and blocking status
- When the number of threads is greater than the number of processors, multiple threads rotate on the same CPU
- Cooperative scheduling strategy: only when a thread calls the sleep() or yield() method will it give up the occupied resources -- that is, the thread must actively give up the occupied resources
- Preemptive scheduling strategy: the system allocates a small period of time to each executable thread to process the task. When the task is completed, the system will deprive the resources occupied by the thread
- The blocked thread will re-enter the ready state at the appropriate time
Thread state transition diagram
3.3 death status
- Test thread death available isAlive()
- The thread in death cannot run again, otherwise an IllegalThreadStateException will be thrown
4. Control thread
4.1 join thread
- If A.join() is called by MainActivity, MainActivity will be blocked. MainActivity will not execute until thread A finishes executing
4.2 daemon thread
- If all foreground threads die, the background thread will die automatically
public class DaemonThread extends Thread { @Override public void run() { for(int i = 0; i< 1000; i++){ System.out.println("DaemonActivity" + i); } } public static void main(String[] args){ DaemonThread thread = new DaemonThread(); thread.setDaemon(true); thread.start(); for(int i = 0; i < 10; i ++ ){ System.out.println("MainActivity" + i); } } }
Operation results
4.3 thread sleep
try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
- After the sleep method pauses the current thread, it will give other threads execution opportunities, regardless of other thread priorities; However, the yield method will only be given to threads with the same or higher priority
- The sleep method will enter the blocking state and will not enter the ready state until the blocking time has elapsed; yield forces the current thread to a ready state
- The sleep method threw an InterruptedException, while the yield method did not throw an exception
4.4 changing thread priority
- High priority threads get more execution opportunities, and low priority threads get less execution opportunities
- setPriority and getPriority methods to set and return the priority of the specified thread
5. Thread synchronization
- The run() method does not have synchronization security
- java introduces synchronization monitor to solve the problem of multithreading synchronization. In synchronized (obj), obj is a shared resource
5.1 synchronization method
- Synchronous method is to use synchronized to modify a method
- The synchronization monitor of the instance method defaults to this
- In Java, immutable classes are always thread safe. Variable class objects need additional methods to ensure their thread safety
public class DaemonThread extends Thread { static int balance = 100; int drawAmount; String name; public DaemonThread(int drawAmount, String name){ this.drawAmount = drawAmount; this.name = name; } @Override public void run() { this.draw(drawAmount); } public synchronized void draw(int amount){ if(balance >= amount){ System.out.println(this.name + "Take it out" + amount); try{ Thread.sleep(1); } catch (InterruptedException e){ e.printStackTrace(); } balance -= amount; System.out.println("\t The balance is" + balance); } else{ System.out.println(this.name + "Cash withdrawal failed"); } } public static void main(String[] args){ new DaemonThread(50, "A").start(); new DaemonThread(100, "B").start(); } }
5.2 release the lock of the synchronization monitor
In the following cases, the thread releases the lock on the synchronization monitor
- The execution of the synchronization method and synchronization code block of the current thread ends
- Encountered break and return
- Exception encountered
- The program executes the wait() method of the synchronization monitor object
It will not be released under the following conditions:
- When the synchronization method is executed, the program calls the Thread.sleep() Thread.yield() method
- Another thread called the thread's suspend method
5.3 synchronization lock
- Starting with Java 5, a more powerful synchronization lock mechanism is provided, which can be achieved by explicitly defining synchronization lock objects
- Lock provides a wider range of locking operations than synchronized, and supports multiple related Condition objects
- Lock type:
Lock
ReadWriteLock
ReentrantLock: commonly used. You can re lock a locked object
ReentrantReadWriteLock
StampedLock
Method name | effect |
---|---|
lock | Lock |
unlock | Unlock |
5.4 deadlock
A et al. B, B et al. A
5.5 thread communication
5.5.1 traditional thread communication
Method name | effect |
---|---|
wait | Causes the current thread to wait until another thread calls the notify() or notifyAll() methods of the synchronization monitor |
notify | Wake up a single thread waiting on this synchronization monitor |
notifyAll | Wake up all threads waiting on this synchronization monitor |
- wait() must be executed with a lock
5.5.2 using Condition
- If synchronized is not applicable in the system to ensure thread synchronization, but Lock object is used to ensure synchronization, then wait, notify, notifyAll() cannot be used for thread communication
- When using Lock objects, Java provides conditions to ensure thread coordination
- The Condition method is as follows
Method name | effect |
---|---|
await | Causes the current thread to wait until another thread calls the signal() or signalAll() methods of the synchronization monitor |
signal | Wake up a single thread on this Lock object |
signalAll | Wake up all threads on this Lock object |
5.5.3 using blocking queues
- Java provides a BlockingQueue interface
- When the producer thread attempts to put elements into the BlockingQueue, if the queue is full, the thread is blocked; When a consumer thread attempts to fetch an element from a BlockingQueue, if the queue is empty, the thread is blocked
Method name | effect |
---|---|
put(E e) | Try putting the E element into the BlockingQueue |
take() | Attempt to fetch an element from the BlockingQueue header |
public class BlockingQueueThread extends Thread { private BlockingQueue<String> bq; public BlockingQueueThread(BlockingQueue<String> bq){ this.bq = bq; } @Override public void run() { String[] strColl = new String[]{ "Java", "Kotlin", "JavaScript" }; for(int i = 0; i < 1000; i ++){ try { System.out.println(getName() + "Start work" + i); bq.put(strColl[i % 3]); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName() + "end-of-job"); } public static void main(String[] args){ BlockingQueue<String> bq = new ArrayBlockingQueue<>(5); new BlockingQueueThread(bq).start(); } }
Result display
It can be seen that Thread-0 has been blocked when it runs for the sixth time, and content cannot be added to it
6. Thread groups and unhandled exceptions
- ThreadGroup refers to thread group, which can classify and manage a batch of threads
- The child thread is in the same thread group as the parent thread that created it
- ThreadGroup method
Method name | effect |
---|---|
int activeCount | Returns the number of active threads in the thread group |
interrupt | Interrupts the number of all active threads in this thread group |
isDaemon | Is the thread group a background thread group |
setDaemon | Set background thread |
setMaxPriority | Sets the highest priority for the thread group |
7. Thread pool
- The thread pool creates a large number of idle threads when the system starts
- The program passes a Runnable object or Callable object to the thread pool, and the thread pool starts a free thread to execute them
- The end of the thread does not die, but returns to the idle state
- After Java 8, an Executors factory class was added to produce thread pools
7.1 ThreadPool
public class ThreadPoolTest { public static void main(String[] args){ ExecutorService pool = Executors.newFixedThreadPool(2); java.lang.Runnable target = () -> { for (int i = 0; i < 100 ; i ++){ System.out.println(Thread.currentThread().getName() + "of i by" +i); } }; pool.submit(target); pool.submit(target); pool.shutdown(); } }
Result display
7.2 ForkJoinPool
- Split a task into multiple small tasks for parallel calculation, and then combine the results of multiple small tasks into the total calculation results
- ForkJoinPool is the implementation class of ExecutorService
public class PrintTask extends RecursiveAction { public static int THREADSH_HOLD = 50; private int start; private int end; public PrintTask(int start, int end){ this.start = start; this.end = end; } @Override protected void compute() { if(end - start < THREADSH_HOLD){ for(int i = start; i < end; i ++){ System.out.println(Thread.currentThread().getName() + "of i by" + i); } } else { PrintTask left = new PrintTask(start, (start + end) / 2); PrintTask right = new PrintTask((start + end) / 2 , end); left.fork(); right.fork(); } } public static void main(String[] args) throws InterruptedException { PrintTask printTask = new PrintTask(0 , 300); ForkJoinPool pool = new ForkJoinPool(); pool.submit(printTask); pool.awaitTermination(2, TimeUnit.SECONDS); pool.shutdown(); } }
Result display
This is a small series to prepare some information for you
Code scanning and wechat for free!