头图

thread group

A ThreadGroup can be used to represent a set of similar or related threads.

A thread group can contain multiple threads and thread groups, and a thread group contains other thread groups, then this thread group is called the parent thread group of these other thread groups. If a thread is not associated with a thread group, then this thread is It belongs to the thread group to which its parent thread belongs. The java virtual machine will specify a thread group for it when it creates the main thread, so any thread in java has a thread group associated with it. We can pass Thread.getThreadGroup( ) to get the thread group associated with the current thread.

Uncaught exceptions and monitoring of threads

When an uncaught exception occurs while a thread is running, the run method exits and the corresponding thread terminates. In this case, we can associate a thread with a UncaughtExceptionHandler before the thread starts, when the thread throws an uncaught exception, the thread will call the UncaughtExceptionHandler.UncaughtException(Thread t, Throwable e) method before exiting, we can Do the corresponding log processing in this method, or recreate a thread to replace this thread.

 public class UncaughtExceptionDemo {
    static class MyExceptionHandler implements Thread.UncaughtExceptionHandler{

        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println(t.getName()+"线程抛出了异常");
            MyThread thread = new MyThread();
            thread.setName("B");
            thread.setUncaughtExceptionHandler(new MyExceptionHandler());
            thread.start();
        }
    }

    static class MyThread extends Thread{
        @Override
        public void run() {
            if ("A".equals(Thread.currentThread().getName())){
                throw new BusinessException("出现异常:"+Thread.currentThread().getName());
            }
            System.out.println(Thread.currentThread().getName());
        }
    }

    static class BusinessException extends RuntimeException{
        public BusinessException(String message) {
            System.out.println(message);
        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.setName("A");
        myThread.setUncaughtExceptionHandler(new MyExceptionHandler());
        myThread.start();
    }
}
===========结果============
出现异常:A
A线程抛出了异常
B

Thread Pool

The benefits of using thread pools

  • Reduce resource consumption: There are reusable threads in the thread pool, which can reduce the performance consumption caused by thread creation and destruction
  • Improve thread response speed: Threads in the thread pool respond directly to tasks, instead of creating threads after responding to tasks
  • Good for thread management

The meaning of each parameter in the thread pool

The responsibilities and processes of each component in the thread pool

  1. Thread pool manager, responsible for thread pool creation, destruction, adding tasks, etc.
  2. worker thread
  3. The task queue is used to temporarily store tasks and can play a role of buffering. Because it is generally in a concurrent scenario, the task queue generally uses BlockingQueue to ensure thread safety.
  4. Tasks, tasks require to implement a uniform interface so that worker threads can execute and process

What is a rejection policy

  1. After the thread pool calls shutdown, the thread pool will wait for all threads in the current thread pool to finish executing, but will not receive new tasks.
  2. The core thread pool is full - the task queue is full - the thread pool has reached the maximum number of threads - the thread pool will not receive new tasks.

Several common rejection strategies

  1. DiscardPolicy: Newly added tasks will be ignored directly
  2. DiscardOldestPolicy: will remove the task at the head of the queue and insert the new task at the end of the queue
  3. AbortPolicy: A runtime exception called RejectedExecutionException will be thrown, which can be reprocessed in the catch
  4. CallerPolicy: When there is a new task but the thread pool is not capable of processing it, it is executed by the thread that submitted the task. (most perfect)

Common thread pool

  1. FixedThreadPool

    A thread pool with a fixed number of threads. The number of core threads is the same as the maximum number of threads. new FixedThreadPool(10) - The number of threads increases from 0 at the beginning, and when it increases to 10, it will no longer increase, and new tasks will be placed in the task queue. When there are new tasks, no new threads will be generated.

  2. CachedThreadPool

    Threads in the thread pool can increase infinitely, but will not exceed Integr.MAX\_VALUE (2^31, almost never reach)

  3. ScheduleThreadPool

    execute tasks periodically

  4. SingleThreadExecutor

    There is only one thread to perform tasks, but when an exception occurs in the current thread, the thread pool will create a new thread to perform subsequent tasks. The advantage is that the tasks performed are ordered.

  5. SingleThreadScheduleExecutor

    Similar to 3 is a special case of ScheduleThreadPool, equivalent to new ScheduledThreadPoolExecutor(1)

  6. ForkJoinPool

    Often used in recursive scenarios such as tree traversal

    The RecursiveTask class is a simple wrapper for ForkJoinTask. At this time, we rewrite the compute() method to return directly when n<=1, and create recursive tasks when n>1, that is, f1 and f2, and then we use fork( ) method to split the tasks and execute them separately. Finally, when returning, use the join() method to aggregate the results, thus realizing the splitting and aggregation of tasks.

     class Fibonacci extends RecursiveTask<Integer> { 
        int n;
    
        public Fibonacci(int n) { 
            this.n = n;
        } 
    
        @Override
        public Integer compute() { 
            if (n <= 1) { 
                return n;
            } 
            Fibonacci f1 = new Fibonacci(n - 1);
            f1.fork();
            Fibonacci f2 = new Fibonacci(n - 2);
            f2.fork();
            return f1.join() + f2.join();
        } 
     }
     
    public static void main(String[] args){ 
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        for (int i = 0; i < 10; i++) { 
            ForkJoinTask task = forkJoinPool.submit(new Fibonacci(i));
            System.out.println(task.get());
        } 
     }

Why is it not recommended to use Executors to create thread pools

The following figure is the blocking queue used by each thread pool.

  1. FixedThreadPool and SingleThreadExecutor

    Because the capacity of LinkBlockingQueue is almost infinite, if the consumption speed of tasks exceeds the task production speed, a large number of tasks will accumulate in the queue, which may lead to memory overflow.

  2. CatchedThreadPool

    When there are many tasks, the thread pool will create unlimited new threads, which may eventually cause the operating system to fail to create new threads or cause memory overflow.

  3. ScheduleThreadPool and SingleThreadScheduleExecutor

    DelayedWorkQueue is also an unbounded queue. If there are a large number of tasks in the queue, it may also overflow the memory.

How to properly shut down a thread pool

  1. shutdown

    After calling this method, the thread pool will not stop immediately but will be completely closed after all tasks in the queue are processed. If there are new task submissions at this time, it will be rejected.

  2. shutdownNow

    Immediately terminate all operations in the thread pool, unsafe, not recommended

  3. isShutdown

    Determine whether the shutdown method is executed. At this time, the thread pool may still be executing the remaining tasks.

  4. isTerminated

    Whether it is completely terminated, that is, execution of shutdown + remaining tasks are executed or shutdownNow is executed

  5. awaitTermination

    awaitTermination(10) - wait for 10 seconds, return true if all tasks are executed within 10 seconds, and return false if not completed within 10 seconds

thread pool monitoring

Thread pool monitoring related methods provided by ThreadPoolExecutor

method use
getPoolSize() Get the current thread pool size
getQueue() Returns an instance of the work queue from which the current size of the work queue can be obtained
getLargestPoolSize() Get the maximum number of worker threads that has ever been reached. This value helps to confirm whether the maximum size of the thread pool is reasonable.
getActiveCount() Get the number of worker threads currently executing tasks in the thread pool (approximate)
getTaskCount() Get the number of tasks received by the thread pool so far (approximately)
getCompletedTaskCount() Get the number of tasks that the thread pool has processed so far (approximately)

eacape
205 声望8 粉丝

JAVA 攻城狮