I: beauty you know thread is what thing yao

My partner: Yes

Me: (surprised) Oh? That you say

My object: Our county is Lulong

Me:…

I have worked for several years. In the process of work, IT took me a long time from the beginning when I thought that except for the basic use of normal threads, I could contact with few scenes of thread problems, to the end when I found that thread problems were everywhere, and finally I felt that I still did not know enough about threads. Personal understanding of threads is about this stage. Begin to know that there are two kinds of threads created when first learning way, know how to run, and then work for a long time, found that everybody is to use a thread pool to create a thread, don’t let to define your own thread running, while also don’t know what that means, but is on the way to do, to later see Meituan article about thread pool, Found to understand the thread is too little, began to add some thread, always refresh yourself in the process of a cognitive, know the thread is has its own life cycle, can also have a return value, create a thread way also so much, so I usually write method is running a thread. The original thread execution order is THE CPU scheduling, the number of threads set so much is to better use the CPU utilization rate, multi-threading will encounter so many problems, want to write a good multi-threaded code originally need to understand so much knowledge……

Simply comb some of their own understanding

The life cycle of a thread

In fact, in our daily work and learning process, we should have been exposed to too many things, such as the life cycle of Java objects, the life cycle of Spring beans and so on. The existence of the life cycle is an inevitable thing, and any behavior can not be said to be in place in one step. Any kind of life cycle, just so that we can have better control over the phases of the object doing what we want to do. The life cycle of a Thread can be simply divided into: created, ready, blocked, and stopped. To see the definition in the code, look at the java.lang.Thread class, which has an internal enumeration class State

create

Create state is when we just created a new thread, which means we’re just ready to run the task, but we haven’t called start yet. In fact, according to my own understanding, we usually implement threads in two ways, one is to create Thread objects and create tasks by ourselves. The other way to create a Thread object is to give it to the Thread pool, so we create our own task object and give it to the Thread pool to execute

Thread

Thread class directly implemented

package cn.yarne;
/** * Created by yarne on 2021/8/21. */
public class Main extends Thread {

    @Override
    public void run(a) {
        System.out.println("hello thread:"+Thread.currentThread().getId());
    }

    public static void main(String[] args) {
        new Main().run();
        newMain().start(); }}Copy the code

Run is a direct call to a method, which is executed synchronously. Start is a process that starts a thread asynchronously

Runnable

Runnable interface implementation

package cn.yarne;
/** * Created by yarne on 2021/8/21. */
public class Main implements Runnable {
    @Override
    public void run(a) {
        System.out.println("hello thread:"+Thread.currentThread().getId());
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.run();
        newThread(main).start(); }}Copy the code

Thread pool creation

We use thread pool to create, more specifically, tasks, not threads, I divide them into two types, one is execute to execute the task, the other is submit to execute the task

execute+Runnable

Execute is a normal task object that implements the Runnable interface. It is no different from the task we created above, but we only need to pass in the task when we call it. The thread that finally executes the task is managed by the thread pool

package cn.yarne;
import java.util.concurrent.*;
/** * Created by yarne on 2021/8/21. */
public class Main implements Runnable{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(new Main());
    }
    @Override
    public void run(a) {
        System.out.println("hello thread:"+Thread.currentThread().getId()); }}Copy the code
submit+Callable/Runnable

Submit has the same meaning as execute, but the only difference is that submit has a return value. It can get a specific return value through the get() method of Future. If there is no return value, it will be Null. Below are three ways to create a task

submit(Runnable)

This is the same as a normal thread, but only after the task thread has finished executing

package cn.yarne;
import java.util.concurrent.*;
/** * Created by yarne on 2021/8/21. */
public class Main implements Runnable{
    public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<? > submit = executorService.submit(new Main());
        System.out.println(submit.get());
        executorService.shutdown();
    }
    @Override
    public void run(a) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello thread:"+Thread.currentThread().getId()); }}Copy the code
submit(Runnable,Result)

This method is the same as above, the difference is that you can define the return result

package cn.yarne;

import java.util.concurrent.*;
/** * Created by yarne on 2021/8/21. */
public class Main implements Runnable{
    public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<? > submit = executorService.submit(new Main(),1);
        System.out.println(submit.get());
        executorService.shutdown();
    }

    @Override
    public void run(a) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello thread:"+Thread.currentThread().getId()); }}Copy the code
submit(Callable)

The most commonly used method is this, because this is the only way to actually get the thread’s return value. Create a task object by implementing the Callable interface, override the Call method to define the task and return value directly

package cn.yarne;
import java.util.concurrent.*;
/** * Created by yarne on 2021/8/21. */
public class Main implements Callable{
    public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<? > submit = executorService.submit(new Main());
        System.out.println(submit.get());
        executorService.shutdown();
    }

    @Override
    public Object call(a) throws Exception {
        System.out.println("hello thread:"+Thread.currentThread().getId());
        return "1"; }}Copy the code

How many ways are there to create a thread?

One way, actually, regardless of how you create it, there’s only one way to actually create Thread objects, and that’s new threads, including Thread pools, and the way a Thread pool creates threads is in factory mode, and if you click on its default factory class, you can actually see that it’s still threads that are created with new threads

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private finalString namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s ! =null)? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix ="pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if(t.getPriority() ! = Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY);returnt; }}Copy the code

ready

When we call start, the thread is ready, why is it ready and not running? Because when we call start, it doesn’t mean that the thread starts executing right away, it just tells the CPU that I’m ready to execute, but when will the CPU be able to execute this thread, It’s out of our control. But the semantics in our normal program are actually running states

blocking

Blocking states summarize the three states in the Thread class

WAITING

There are three methods that leave the thread in a WAITING state after execution

         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
Copy the code
Object.wait

The first is that after we call wait(), the specified thread is in a waiting state and needs to wake up with notify(). Threads in this state, instead of occupying CPU resources, give up resources and enter the waiting area themselves. Wait(), notify(), and notifyAll() are all methods of Object. Therefore, wait is not only a function of waiting in threads, but also the semantics of Object class: Wait(), notify() and notifyAll() must be used in synchronized lock. Wait method can make the current thread give up CPU resources. And release the lock resource so that other threads can normally compete to hold the lock and access the lock resource, which is usually used when we want to suspend the current thread and allow other threads to run the current syschronized synchronized lock resource

Thread.join

Wait for the thread to stop. Wait for the thread to stop. Wait for the thread to stop. Thread1.join () means that the current thread must wait for thread1 to finish before continuing

LockSupport.park

The third is that after calling the park method in LockSupport, the current thread is in waiting state and needs to wait for the unpark method to be manually called before it can continue running. And wait the difference is, park method under the state of waiting, not releasing the lock resources will have been occupied, there is a want to mention is that if the first unpark method, regardless of whether the current thread below several park, it won’t take effect again

BLOCKED

When a thread is awakened by notify, it does not immediately enter the state of obtaining CPU resources. Instead, it is in the state of queuing for obtaining synchronized lock. Get into a normal state.

TIMED_WAITING

In fact, the thread is in a waiting state, but it does not mean that it needs to wait for some instruction to wake up, but that it has a fixed waiting time, when the time is up, it will automatically wake up. All the following five methods in this state can enter after execution. However, whether the lock resource should be released after execution or waiting state is not uniform, but determined according to the method type

         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
Copy the code
Object.wait(long)

Release CPU resources and lock resources

Thread.sleep(long)

CPU resources are released but lock resources are not released

Thread.jon(long)

Release CPU resources and lock resources

LockSupport.parkNanos(long)

Like Park, the time is nanosecond

LockSupport.parkUntil(long)

As with Park, the time comes to automatically unpark

The destruction

The task in the thread run method completes and is destroyed

The thread pool

Why thread pools

I think can take single example to compare the thread pool, if our singleton pattern is used in order not to create duplicate objects, lead to waste of resources, so the purpose of the thread pool design in fact, because create a thread is a complex process, if every time to use new one out, when a lot of work need to be done at the same time, It’s a huge waste of time and resources. Using the thread pool to manage the thread life cycle can make the threads in the thread pool not to be created repeatedly, and can be used as a recycling machine, saving a lot of repetitive work, improving efficiency and reducing pressure.

How do I define a thread pool

By default, Java provides four ways to create thread pools

  1. Executors.newSingleThreadExecutor()Singleton thread pool, run by a single thread
  2. Executors.newCachedThreadPoo()The cache thread pool, as long as there is free CPU resources, can constantly create new threads, when idle to recycle
  3. Executors.newFixedThreadPool(int)A thread pool of a fixed size will always grow to the maximum we set when there are not enough threads, and no idle threads will be reclaimed
  4. Executors.newScheduledThreadPool(int)Fixed size thread pool, can set the execution time, according to our set time period to execute the task

Custom thread pools

The documentation doesn’t recommend using the default thread pool, even though it’s easy to use, because it’s really hard to match the default four thread pools to our needs when we actually use thread pools. And it may cause some problems, such as singletons and fixed size thread pool, although it seems to meet our needs, but the internal blocking queue is an indefinite length of queue, may be accumulated all the time, causing thread congestion. And then the other two caches and task thread pools, they set the size of the thread pool to integer.max_value, which is obviously a problem. The thread pool will keep creating new threads indefinitely. If there are really a lot of tasks, the thread pool will just fill up the CPU. Even say memory overflow and so on.

How do I customize the thread pool

In fact, the custom thread pool is very simple, and the Java default several thread pool creation method is the same, we can see the code in fact, four different types of thread pool just said with different parameters to do the encapsulation.

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
Copy the code
 public static ExecutorService newSingleThreadExecutor(a) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1.1.0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
Copy the code
public static ExecutorService newCachedThreadPool(a) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
Copy the code
public class ScheduledThreadPoolExecutor
        extends ThreadPoolExecutor
        implements ScheduledExecutorService {...public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return newScheduledThreadPoolExecutor(corePoolSize); }...public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              newDelayedWorkQueue()); }...Copy the code

As you can see from the code above, whichever implementation is ultimately based on the ThreadPoolExecutor thread pool, we can customize the thread pool in the same way as they do, with parameters

Custom thread pool parameters

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
Copy the code
  • corePoolSize: Reserved in the thread poolCore threadsIf the number of threads in the thread pool does not reach the core thread count, the thread pool will create a new thread even if there are free and available threads.
  • maximumPoolSize: the thread poolMaximum number of threadsIf there are not enough core threads, new threads will be created until the maximum
  • keepAliveTime + TimeUnit: idle threadSurvival time and unitsMake sure that threads destroy some idle threads when appropriate, and that the thread pool is as limited to core threads as possible
  • BlockingQueue:The work queueIf the number of threads reaches the core number, new threads start filling the queue. If the queue is full, new threads are created until the maximum number of threads is reached. This queue will be consumed by idle threads.
  • ThreadFactory: This is createThread factories, the default thread pool factory thread name generation is relatively simple, just a number of cumulative, it is not convenient for us to troubleshoot problems, generally we are advised to implement the thread factory according to their own needs
  • RejectedExecutionHandler: Reject policy, when the maximum number of threads can not handle, can set how to handle the new task, the default provides four, we can also implement
    • AbortPolicy(Default) : Rejection is thrownRejectedExecutionExceptionabnormal
    • CallerRunsPolicy: Reject subsequent tasksExecute directly in the main thread of the calling thread pool execution
    • rejectedExecution: After the task is rejected, it is directly put into the work queue in the thread poolDelete the oldest task and add this task
    • DiscardPolicy: After a mission is rejected, directlyDiscarding the taskAnd don’t

What are the problems with multithreading

Space problem, continue in the next article

conclusion

Article mainly introduced the life cycle of a thread, the thread pool, some basic concepts, around these concepts, the part of the personal understanding of the principle of a true understanding of threads and thread pool and use, will make us in the process of development of thread handle more follow one’s inclinations, multithreading problems will continue to explain in the next article.