当前位置:网站首页>[concurrent programming JUC] four ways to create threads

[concurrent programming JUC] four ways to create threads

2022-06-10 10:22:00 Looking at the stars

1 Inherit Thread Create thread

  1. Inherit Thread class , rewrite run() Method .
  2. Create an instance of the subclass
  3. Use start() Method to start the thread .
public class MyThread extends Thread{
    
    @Override
    public void run() {
    
        System.out.println(Thread.currentThread().getName() + ": Running!");
    }

    public static void main(String[] args) {
    
        MyThread t = new MyThread();
        t.setName("t1");
        t.start();
    }
}

How to write anonymous inner class

public class MyThread{
    
    public static void main(String[] args) {
    
        Thread t = new Thread() {
    
            @Override
            public void run() {
    
                System.out.println(Thread.currentThread().getName() + ": Running!");
            }
        };
        t.setName("t1");
        t.start();
    }
}

2 adopt Runable Create thread

  1. Definition Runnable Implementation class of interface , rewrite run Method ( Executor )
  2. establish Runnable Instance of implementation class , Take this example as Thread Of target objects creating Thread object .
  3. call start() Start the thread .

hold 【 Threads 】 and 【 Mission 】( Code to execute ) Separate

public class MethodA implements Runnable{
    
    @Override
    public void run() {
    
        System.out.println(Thread.currentThread().getName() + ": Running!");
    }

    public static void main(String[] args) {
    
        Runnable r = new MethodA();
        Thread t1 = new Thread(r);
        t1.setName("t1");
        t1.start();
    }
}

How to write anonymous inner class

public class MyThread{
    
    public static void main(String[] args) {
    
        Thread t = new Thread(new Runnable() {
    
            @Override
            public void run() {
    
                System.out.println(Thread.currentThread().getName() + ": Running!");
            }
        });
        t.setName("t1");
        t.start();
    }
}

Lambda Expression simplification

public class MyThread{
    
    public static void main(String[] args) {
    
        Thread t = new Thread(() -> System.out.println(Thread.currentThread().getName() + ": Running!"));
        t.setName("t1");
        t.start();
    }
}

Thread And Runnable The relationship between

Thread Realized Runnable

class Thread implements Runnable {
    ...}

therefore , stay Thread Internal to achieve Runnable Methods in the interface run(). You can see , When target Isn't empty , stay run() Method target.run().

@Override
public void run() {
    
    if (target != null) {
    
        target.run();
    }
}

So let's take a look at target What is it? , In the initialization method init() in .

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
    
	...
	this.target = target;
	...
}

therefore ,target It's an implementation Runnable Interface .

therefore , If you create a Runnable The object is to Thread, that Thread Running is a Runnable Object run Method ; If you don't create Runnable object , It needs to be rewritten run Method ,Thread Will run this rewritten run Method .

3 adopt Callable and FutureTask Create thread

  1. establish Callable Implementation class of interface , Realization call Method ( Executor , There is a return value ), And create Callable Objects that implement classes .
  2. Use FutureTask Class to packaging Callable object , The FutureTask Object encapsulates the Callable Object's call() Return value of method .
  3. Use FutureTask Object as Thread Object's target Create and start the thread .
  4. call FutureTask Object's get() Method to get the return value after the execution of the child thread .

And 【Runnable】 comparison , You can have a return value , adopt get() Method to get the return value after the execution of the child thread .

public class MyThread{
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    
        //  establish Callable Implementation class object of interface 
        Callable<Integer> callable = new Callable<Integer>() {
    
            @Override
            public Integer call() throws Exception {
    
                System.out.println(Thread.currentThread().getName() + ": Running!");
                return 1;
            }
        };
        //  Use FutureTask Class to packaging Callable object 
        FutureTask<Integer> task = new FutureTask<>(callable);

        //  Use FutureTask Object as Thread Object's target Create and start the thread 
        Thread thread = new Thread(task, "t1");
        thread.start();

        //  Block to get results 
        System.out.println("call Return value of method : " + task.get());

    }
}

4 Thread pool creates threads

4.1 Thread parameter description

/** *  Create a new... With the given initial parameters ThreadPoolExecutor. */
public ThreadPoolExecutor(int corePoolSize,// Number of core threads in thread pool 
                          int maximumPoolSize,// The maximum number of threads in the thread pool 
                          long keepAliveTime,// When the number of threads is greater than the number of core threads , The maximum time an extra idle thread can survive 
                          TimeUnit unit,// Time unit 
                          BlockingQueue<Runnable> workQueue,// Task queue , Used to store a queue of waiting tasks 
                          ThreadFactory threadFactory,// Thread factory , Used to create threads , General default 
                          RejectedExecutionHandler handler// Refusal strategy , When too many tasks are submitted that cannot be processed in time , We can customize strategies to handle tasks 
                         ) {
    
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

Important parameter

  • corePoolSize: Number of core threads , Its number determines that the added task is to open up new threads to execute , Or put it in workQueue In the task queue .
  • maximumPoolSize: Maximum number of threads , This parameter will be based on what you use workQueue Type of task queue , Determine the maximum number of threads that the thread pool will open .
  • keepAliveTime: The number of idle threads in the current thread pool exceeds corePoolSize when , How long will extra threads be destroyed .
  • unit:keepAliveTime The unit of
  • workQueue: Task queue , Used to store queues waiting for tasks to be executed ; It is generally divided into direct submission queues 、 Bounded task queue 、 Boundless task queue 、 Priority queue .
  • threadFactory: Thread factory , Used for thread creation , General default .
  • handler: Refusal strategy ; When there are too many tasks to handle , You can customize policies to handle tasks .

🧭 Number of core threads and maximum number of threads

  • Fewer new tasks have been submitted corePoolSize, Even if other worker threads are idle , New threads will also be created to handle .

  • The new task submitted is greater than corePoolSize, Less than maximumPoolSize, New threads are created only when the queue is full

  • By setting corePoolSize and maximumPoolSize identical , You can create a fixed size thread pool .

  • take maximumPoolSize Set to Integer.MAX_VALUE, Can accommodate any number of concurrent numbers .

  • have access to setCorePoolSize and setMaximumSize Make dynamic changes .

  • When the number of threads reaches maximumPoolSize When the queue is full, the rejection policy will be executed .

 Insert picture description here
Task queue workQueue

  1. Direct submission queue ,SynchronousQueue It's a special one BlockingQueue, He has no capacity , Submitted tasks will not be saved , Always submit for execution right away , Every insert operation will block , You need to perform another delete operation to wake up , On the contrary, each delete operation also needs to wait for the corresponding insert operation .
  2. Bounded task queues ,ArrayBlockingQueue, If a new task needs to be performed , The thread pool will create new threads , Until the creation quantity reaches corePoolSzie when , New tasks will be added to the waiting queue . If multiple columns are full , The number of threads to be created continues to reach maximumPoolSize, If the number of threads is greater than maximumuPoolSize, A reject policy is executed .
  3. Boundless task queue ,LinkedBlockingQueue, The task queue can add new tasks without restriction , The maximum number of thread pools created is corePoolSize,maximumPoolSize This parameter is invalid .( When the capacity is not set , The default size is Integer.MAX_VALUE, It can be regarded as boundless )
  4. Priority task queue ,ProrityBlockingQueue, Special unbounded queue , The maximum number of thread pools created is corePoolSize,maximumPoolSize This parameter is invalid . Generally, queues process tasks according to the first in first out rule , The queue can be customized to execute rules according to priority .

Refusal strategy

When the queue is full and the number of threads created by the thread pool reaches the maximum number of threads , You need to specify a denial policy to handle thread pool overload .

  1. AbortPolicy Strategy : Throw an exception directly , Prevent the system from working properly .
  2. CallerRunsPolicy Strategy : If the number of threads in the thread pool reaches the maximum , This policy will run the tasks in the task queue in the caller thread .
  3. DiscardOldestPolicy Strategy : Discard the oldest task in the task queue , And try to submit again .
  4. DiscardPolicy Strategy : Discard the task directly .

Close thread pool

shutdownNow(): Close thread pool now ( violence ), Ongoing and queued tasks will be interrupted , At the same time, this method will return the task list in the interrupted queue
shutdown(): Smoothly close the thread pool , The tasks in progress and in the queue can be completed , Subsequent incoming tasks will be rejected
isTerminated(): When the task being executed and all the tasks in the column are executed ( Empty ) It will return to true

4.2 Create thread

Thread pools can be created automatically or manually , Automatic creation is reflected in Executors In the tool class , Common can create newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool;

Manual creation is reflected in the flexible setting of various parameters of thread pool , Embodied in the code, that is ThreadPoolExecutor The difference of each argument on the class constructor .

4.2.1 newFixedThreadPool()

Create a fixed-size thread pool

Executors.newFixedThreadPool(2)

Test code :

public class MyThread{
    

    public static void main(String[] args) {
    
    	//  Create up to 2 Thread pool with a number of threads . 
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 10; i++) {
    
            executorService.execute(new MethodA());
        }
    }
}

The construction method used is

new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())

Set up corePoolSize=maxPoolSize,keepAliveTime=0( This parameter has no effect at this time ), Unbounded queue , Tasks can be put into , When there are too many requests ( The task processing speed cannot keep up with the task submission speed, resulting in request accumulation ) It may cause excessive memory consumption or directly cause OOM abnormal

4.2.2 newSingleThreadExecutor()

Create a thread pool with only one thread

Executors.newSingleThreadExecutor()

Test code :

public class MyThread{
    

    public static void main(String[] args) {
    
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
    
            executorService.execute(new MethodA());
        }
    }
}

The construction method used is

new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), var0)

Basically the same newFixedThreadPool, But set the number of threads to 1, Single thread , Disadvantages and newFixedThreadPool Agreement .

4.2.3 newCachedThreadPool()

Create a thread pool with unlimited threads , Any submitted tasks will be executed immediately

Executors.newCachedThreadPool();

Test code :

public class MyThread{
    

    public static void main(String[] args) {
    
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
    
            executorService.execute(new MethodA());
        }
    }
}

The construction method used is

new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue())

corePoolSize=0,maxPoolSize For a large number , Synchronous handover queue , That is, resident threads are not maintained ( Core thread ), Each time a request is made, a new thread is created directly to handle the task , Queue buffering is also not used , Will automatically recycle redundant threads , Because will maxPoolSize Set to Integer.MAX_VALUE, When there are many requests, it is possible to create too many threads , Lead to exhaustion of resources OOM

4.2.4 newScheduledThreadPool()

Support regular periodic execution , Note that you are using a delay queue

Executors.newScheduledThreadPool(2)

Test code :

public class MyThread{
    

    public static void main(String[] args) {
    
        ExecutorService executorService = Executors.newScheduledThreadPool(2);
        for (int i = 0; i < 10; i++) {
    
            executorService.execute(new MethodA());
        }
    }
}

The construction method used is

new ThreadPoolExecutor(var1, Integer.MAX_VALUE, 0L, TimeUnit.NANOSECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue())

Support regular periodic execution , Note that you are using a delay queue , The disadvantages are the same as newCachedThreadPool Agreement

4.2.4 ThreadPoolExecutor()

原网站

版权声明
本文为[Looking at the stars]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/161/202206100953571233.html