What is a thread?

** Thread is the smallest unit of operation that the operating system can schedule. It is contained in a process and is the actual unit of operation in the process. ** Programmers can use it for multiprocessor programming, and you can use multiple threads to speed up computationally intensive tasks. For example, if it takes one thread 100 milliseconds to complete a task, it takes 10 threads 10 milliseconds to complete the task. Java provides excellent support for multithreading at the language level and is a great selling point.

How do I create a thread?

There are three main methods:

The first is to override the run method by inheriting Thread.

Second: implement the Runnable interface and override the run method.

The third implements the Callable<> interface and overwrites the call method.

The interviewer is sure to ask what are the pros and cons of these two approaches?

Answer: Runnable is implemented by implementing its interface, and Thread is implemented by inheriting its class. The most obvious difference between the two implementations is that since Java does not allow multiple inheritance, the implementation of Runnable interfaces can inherit from other classes, but Thread clearly cannot. It can also be seen from the source code of Thread that when resource sharing is implemented in the form of Thread, the source code actually transforms Thread downward into Runnable. In fact, the internal resource sharing is still implemented in the form of Runnable.

We will come to the conclusion that approach two should be used, because object orientation advocates less inheritance and more composition.

What’s the difference between the start() and run() methods in the Thread class?

This question is often asked, but it can be a good indicator of the candidate’s understanding of the Java threading model. The start() method is used to start the newly created thread, and start() internally calls the run() method, which has a different effect than calling the run() method directly. When you call the run() method, it will only be called from the original thread. The start() method will only start a new thread if no new thread is started.

What is the difference between Runnable and Callable in Java?

Both Runnable and Callable represent tasks that need to be executed in different threads. Runnable has been available since JDK1.0, and Callable was added in JDK1.5. The main difference is that Callable’s call() method can return values and throw exceptions, while Runnable’s run() method does not. Callable returns a Future object loaded with the result of the computation.

Thread pool concepts and advantages

Thread pool (English: Thread pool) : A thread usage pattern. Too many lines lead to scheduling overhead, which affects cache locality and overall performance. A thread pool maintains multiple threads waiting to be assigned tasks that can be executed concurrently by the supervisor. This avoids the cost of creating and destroying threads when processing short tasks

Advantages of thread pools

(1) Reduce the consumption of system resources. By reusing existing threads, reduce the consumption caused by the creation and destruction of threads;

(2) Improve the response speed of the system. When a task arrives, it can be executed immediately without waiting for the creation of new threads by reusing existing threads;

(3) Convenient control of concurrent number of threads. If threads are created without limit, they will use too much memory to generate an OOM, and will cause CPU to switch too much (CPU switching costs time (you need to keep the current thread in the field and restore the thread in the field)).

(4) Provide more powerful function, delay timing thread pool.

Multi-threaded optimization and performance comparison

ThreadPool +CountDownLatch (program counter)

CountDownLatch is, as the name implies, a thread counter, which is executed as follows: first, the await() method is called on the main thread, which blocks, then the program counter is passed as an argument to the thread object, and finally, after each thread completes the task, the countDown() method is called to indicate completion. Await () on the main thread becomes invalid after countDown() has been executed multiple times.

 

The second: Fork/Join framework

From version 7 onwards, the Fork/ Join framework was introduced. Literally, Fork means split, join means merge, so the idea behind the framework is. Fork is used to split tasks, and then join is used to combine the results of each person’s execution after the split.

For example, if we want to calculate the numbers that are added continuously, 2+4+5+7=? We can split this operation into two sub-tasks, one to calculate 2+4, and the other to calculate 5+7. This is the process of Fork. After the calculation is completed, the calculation results of these two sub-tasks are summarized to get the sum, which is the process of join.

Fork/Join framework implementation idea: First, divide the task, use Fork class to divide the large task into several sub-tasks, the process of dividing needs to be according to the actual situation, until the divided task is small enough. Then, the join class executes the task. The subtasks are divided into different queues. Several threads obtain the task from the queue and execute it, and the finished result is put into a separate queue.

The Fork/Join framework uses several classes. To use the Fork/Join framework, you need to extend the ForkJoinTask class first. Usually, you only need to extend its subclasses RecursiveTask or RecursiveAction. RecursiveTask, for scenarios that have returned results, and RecursiveAction, for scenarios that do not. The execution of a ForkJoinTask requires a ForkJoinPool, which is used to maintain that the subtasks are added to different task queues.

The third JDK8 parallel flow, the following is the multithreaded processing performance of these ways to do a comparison summary.

Parallel streams are one of the new features in JDK8. The idea is to turn a sequential stream into a concurrent stream by calling the parallel() method.

Parallel flow divides a stream into multiple data blocks, uses different threads to process the streams of different data blocks, and finally merges the processing results of the data flows of each block, similar to the Fork/Join framework.

The common thread pool ForkJoinPool is used by default, and the number of threads can be adjusted according to the number of cores of the machine. The adjustment of the number of threads is achieved in the following ways

For a single-thread reference, the most time-consuming is the native Fork/Join framework, which, despite having a number of thread pools configured, is less effective than the JDK8 parallel flow with a precise number of thread pools configured. ParallelStream implementation code is simple and easy to understand, do not need us to write redundant for loop, a parallelStream method to do all, the amount of code greatly reduced, in fact, the bottom of the parallelStream or use the Fork/Join framework, which requires us in the development process of flexible use of various technologies, distinguish the advantages and disadvantages of various technologies, So as to be able to better serve us.