Before we get into multithreading we need to know a few things about the operating system.

A, procedures, processes, threads

1. The program (the program)

Concept: A collection of instructions written in a language to accomplish a specific task. A static piece of code.

2. The process (process)

Concept: an execution of a program, or a running program. Note: As a unit of resource allocation, the system allocates a different memory area for each process during runtime

3. The thread (thread)

Concept: A process can be further refined into a thread, which is a path of execution within a program. Note: thread as a scheduling and execution of the unit, each thread has an independent running stack and program counter (PC), thread switching overhead is small.

Memory structure:

Processes can be refined into multiple threads. Each thread, has its own independent: stack, program counter multiple threads, sharing the same process structure: method area, heap.

Parallelism and concurrency

1. Single-core cpus and multi-core cpus

  • Single-core CPU, in fact, is a false multithreading, because in a time unit, can only execute the task of one thread. In terms of the way the CPU processes threads, the CPU can only process one thread per unit of time (that is, in a time slice), so it blocks the other threads, puts them in the blocking queue, and waits until the current thread is finished processing the new thread from the ready queue for processing. Since switching and processing times are too fast to be perceived by the user, the user assumes that the CPU is processing multiple threads at the same time.
  • Multi-core CPU, in order to better play the efficiency of multi-threading. (Today’s servers are multi-core.)
  • A Java application java.exe has at least three threads: the main thread (), the garbage collector () thread, and the exception handler thread. Of course, if an exception occurs, the main thread will be affected.

2. Understanding of parallelism and concurrency

Parallel: Multiple cpus perform multiple tasks simultaneously. For example: multiple people doing different things at the same time.

Concurrency: a CPU(using time slices) executes multiple tasks simultaneously. For example: second kill, more than one person to do the same thing

Why multithreading?

When we are shopping for goods, there is always a timer counting down on the payment button, but we can still check the product information at this time. This timer and the thread of browsing the product information are running at the same time, so as to realize the shopping scene and increase the user experience.

Advantages of multithreaded programs:

  1. Improve application responsiveness. It makes more sense for graphical interfaces and enhances the user experience.
  2. Improve the CPU utilization of computer system.
  3. Improve program structure. Long and complex processes are divided into multiple threads and run independently, making it easier to understand and modify.

Application Scenarios

  1. Programs need to perform two or more tasks simultaneously.
  2. The program needs to implement some tasks that need to wait, such as user input, file read and write operations, network operations, search, etc
  3. Need some background running programs

Third, Thread class

The JVM for the Java language allows a program to run multiple threads, as represented by the java.lang. Thread class

1. Features of the Thread class

Each Thread is operated by the run() method of a particular Thread object. The body of the run() method is often called the Thread body. The Thread is started by the start (method of the Thread object, rather than by calling run directly

2. Constructor:

  • Thread() : Creates a new Thread object
  • Thread (String threadName) : Creates a Thread and specifies the Thread instance name
  • Thread (Runnable target) : Specifies the target object to create the Thread, which implements the Run method in the Runnable interface
  • Thread (Runnable target, String name) : Creates a new Thread object

3. Two ways to create multiple threads

3.1. Method 1 inherits Thread class:

  1. Create a subclass that extends from Thread
  2. Override the run() class of Thread –> declare the operations performed by this Thread in run()
  3. Object that creates a subclass of Thread
  4. Call start() from this object: ① Start the current thread ② call the current thread’s run()

Note:

  1. To start a thread, you must call start(), not run(). If you start another Thread, you must create an object subclass of Thread and call start() on that object.
  2. If you call the run() method by hand, it’s just a normal method and you don’t start multithreading
  3. The run method is called by the JVM, and control over when it is called and the procedure it executes is determined by the OPERATING system’s CPU scheduling.
  4. To start multithreading, you must call the start method.
  5. A thread object can only be called once the start () method starts, if repeated calls, will throw an exception “lllegalThreadStateException”.

Code sample

//1. Inherit Thread
class MyThread extends Thread {
    public MyThread(a) {}//2. Rerun the run method
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) {
            if (i % 2= =0) { System.out.println(i); }}}}public class ThreadTest {
    public static void main(String[] args) {
3. Create a Thread object
        MyThread myThread = new MyThread();
        //4. Call startmyThread.start(); }}Copy the code

3.2. Mode 2 Implementation of the Runnable interface:

  1. Create a class that implements the Runnable interface
  2. Implement classes to implement abstract methods in Runnable: run()
  3. Create an object that implements the class
  4. Pass this object as an argument to the constructor of The Thread class to create an object of the Thread class
  5. Call start() from an object of the Thread class

Code examples:

Create a class that implements the Runnable interface
public class RunnableTest implements Runnable {
    // 2. Implement the abstract method in Runnable: run()
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) { System.out.println(i); }}}class test {
    public static void main(String[] args) {
        //3. Create an object for the implementation class
        RunnableTest runnableTest = new RunnableTest();
        //4. Pass this object as an argument to the constructor of Thread to create an object of Thread
        Thread thread = new Thread(runnableTest);
        //5. Call start() from the Thread objectthread.start(); }}Copy the code

Comparison of the two ways:

Preferred in development: how to implement the Runnable interface

The reason:

1. The way to achieve the limitations of class single inheritance

2. The implementation is more suitable to handle multiple threads sharing data.

**public class Thread implements Runnable

** Similarities: ** Both methods require overwriting run() to declare the logic to be executed by the thread in run(). In both cases, we call start() in the Thread class to start a Thread.

You can also create anonymous classes

public class ThreadDemo {
    public static void main(String[] args) {

        // Create an anonymous subclass of Thread
        new Thread() {
            @Override
            public void run(a) {
                for (int i = 0; i < 100; i++) {
                    if (i % 2= =0) {
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run(a) {
                for (int i = 0; i < 100; i++) {
                    if (i % 2! =0) {
                        System.out.println(Thread.currentThread().getName() + ":"+ i); } } } }.start(); }}Copy the code

4. Common methods of Thread class

4.1 Common methods:

  1. Start (): Starts the current thread; Call the current Thread’s run(). Only Thread and its subclasses can call the start() method

  2. Run (): It is common to override this method in the Thread class to declare the operations to be performed by the created Thread

  3. CurrentThread (): Static method that returns the thread executing the current code

  4. GetName (): Gets the name of the current thread

  5. SetName (): Sets the name of the current thread

  6. Yield (): Releases the execution of the current CPU

  7. Join (): thread A calls thread B’s join(), and thread A blocks until thread B completes its execution.

  8. Stop (): obsolete. When this method is executed, the current thread is forced to terminate.

  9. Sleep (Long Millitime): Allows the current thread to “sleep” the specified Millitime millisecond. The current thread is blocked for the specified Millitime millisecond.

  10. IsAlive (): checks whether the current thread isAlive

4.2 Thread Priority:

  • MAX_PRIORITY: 10
  • MIN _PRIORITY: 1
  • NORM_PRIORITY: 5 –> Default priority

Gets and sets the priority of the current thread:

  • GetPriority (): Gets the priority of the thread

  • SetPriority (int p): Sets the priority of the thread

Note: a thread of higher priority preempts the CPU of a thread of lower priority. But only probabilistically, high-priority threads are executed with high probability. It does not mean that the low-priority thread executes only when the high-priority thread finishes.

Thread communication: Wait ()/notify()/notifyAll() : These three methods are defined in the Object class.

Classification of threads

  • Daemon threads, such as garbage collection threads, are dependent on the main thread
  • User threads, such as the main thread

5. Lifecycle of the Thread

There are five states of a thread:

  • New: When an object of the Thread class or its subclass is declared and created, the newly created Thread object is in the new state
  • Ready: After a thread in the new state is starred (), it is queued to wait for a CPU slice. At this point, it is ready to run but has not been allocated CPU resources
  • Run: When a ready thread is scheduled and CPU resources are acquired, the run() method defines the actions and functions of the thread
  • Blocking: When the union is manually suspended or an INPUT/output operation is performed under a special circumstance, it temporarily suspends itself and enters a blocking state
  • Death: a thread that has completed all of its work or that has been forcibly terminated or terminated prematurely by an exception

Description:

  1. The lifecycle focuses on two concepts: state and corresponding methods

  2. Attention: State A –> state B: Which methods execute (callback method) a method is actively called: state A –> state B

  3. Blocked: temporary state, not final state

  4. Death: Final state.

Fourth, the synchronization mechanism of threads

1. The background

Example: Create a window to sell tickets for 100 tickets. Use the Runnable interface implementation

  • Problem: in the process of selling tickets, there are duplicate tickets, wrong tickets –> there are thread security problems
  • The reason for the problem is that while one thread is operating on a ticket, while the operation is not complete, other threads join in and also operate on the ticket.
  • How to solve this problem: When thread A operates ticket, other threads cannot participate. Until thread A finishes operating ticket, other threads can operate ticket. This condition cannot be changed even if thread A is blocked.

2. Java solution: Synchronization mechanism

In Java, we address thread safety through synchronization.

2.1 Method 1: Synchronize Code Blocks

synchronized(Synchronization monitor){A synchronization monitor is a common object that needs to synchronize threads
   // The code to be synchronized
    
}

Copy the code

Description:

  1. Code that operates on shared data is code that needs to be synchronized. Can’t contain too much code, can’t contain too little code.
  2. Shared data: Variables that are operated on by multiple threads. For example, ticket is shared data.
  3. Synchronization monitor, commonly known as lock. An object of any class can act as a lock.
  4. Multiple threads must share the same lock.
  • In the way we implement the Runnable interface to create multiple threads, we can consider using this as a synchronization monitor.

  • Beware of using this as a synchronization monitor when creating multiple threads by inheriting the Thread class, and consider using the current class as a synchronization monitor.

Code examples:

Inherit Runnable interface form synchronization code blocks

public class Ticket implements Runnable {
    private int tick = 100;

    @Override
    public void run(a) {

        while (true) {
            synchronized (this) {
                if (tick > 0) {
                    System.out.println(Thread.currentThread().getName() + "Tickets at window number:" + tick--);
                } else {
                    break;
                }
            }
        }
    }
}

class TicketTest {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        Thread thread1 = new Thread(ticket);
        Thread thread2 = new Thread(ticket);
        Thread thread3 = new Thread(ticket);

        thread1.setName("Window 1");
        thread2.setName("Window 2");
        thread3.setName("Window 3"); thread1.start(); thread2.start(); thread3.start(); }}Copy the code

Synchronize code blocks in the form of Thread class inheritance

public class Ticket2 extends Thread {
    private static int tick = 100;
    private static Object object = new Object();

    public Ticket2(a) {}@Override
    public void run(a) {

        while (true) {
            synchronized (object) {
            Synchronized (ticket2.class) {// use reflection to call the current class
                if (tick > 0) {
                    System.out.println(Thread.currentThread().getName() + "Ticket at window number two, ticket number is." + tick--);
                } else {
                    break;
                }
            }

        }
    }
}

class TicketTest2 {
    public static void main(String[] args) {
        Ticket2 ticket1 = new Ticket2();
        Ticket2 ticket2 = new Ticket2();
        Ticket2 ticket3 = new Ticket2();

        ticket1.setName("Window 1");
        ticket2.setName("Window 2");
        ticket3.setName("Window 3"); ticket1.start(); ticket2.start(); ticket3.start(); }}Copy the code

2.2 Method 2: Synchronization Method

If the code that operates on shared data is fully declared in a method, we might as well declare the method synchronized.

public synchronized void show(String namer){... }Copy the code

Code examples:

public class Ticket3 implements Runnable {
    private int tick = 100;
    private boolean isFlag = true;

    @Override
    public void run(a) {
        while(isFlag) { show(); }}public synchronized void show(a) {// Synchronize the show method with the Thread method, and add static to the method to ensure that multiple objects are not created
        if (tick > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "Tickets at window number:" + tick--);
        } else {
            isFlag = false; }}}class TicketTest3 {
    public static void main(String[] args) {
        Ticket3 ticket = new Ticket3();

        Thread thread1 = new Thread(ticket);
        Thread thread2 = new Thread(ticket);
        Thread thread3 = new Thread(ticket);

        thread1.setName("Window 1");
        thread2.setName("Window 2");
        thread3.setName("Window 3"); thread1.start(); thread2.start(); thread3.start(); }}Copy the code

2.3 Method 3: Lock – new in JDK 5.0

  • Since JDK 5.0, Java has provided a more powerful thread synchronization mechanism — synchronization is achieved by explicitly defining a synchronization lock object. A synchronous Lock is acted by using a Lock object.
  • Java. Util. Concurrent. The locks. Lock interface is the tool of control multiple threads to Shared resources access. A Lock provides exclusive access to a shared resource. Only one thread at a time can Lock the Lock object. The thread must acquire the Lock object before starting to access the shared resource.
  • The ReentrantLock class implements Lock, which has the same concurrency and memory semantics as synchronized. In implementing thread-safe control, ReentrantLock is commonly used to explicitly Lock and release locks.
class A {
    Instantiate the ReentrantLock object
    private final ReenTrantLock lock = new ReenTrantLook();
    public void m (a){
        lock.lock/ / 2. The first lock
        try{
            // Code to ensure thread synchronization
        }finally{
            lock.unlock();/ / 3. After the unlock}}}// Note: If the synchronization block is abnormal, write the unlock() statement in the finally block

Copy the code

Code examples:

class Window implements Runnable{

    private int ticket = 100;
    1. Instantiate ReentrantLock
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run(a) {
        while(true) {try{

                //2. Call the lock method lock()
                lock.lock();

                if(ticket > 0) {try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ": Ticket number:" + ticket);
                    ticket--;
                }else{
                    break; }}finally {
                //3. Unlock ()lock.unlock(); }}}}public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("Window 1");
        t2.setName("Window 2");
        t3.setName("Window 3"); t1.start(); t2.start(); t3.start(); }}Copy the code

3. Summary of synchronization methods:

In Thinking in Java, it goes like this: For concurrent work, you need a way to prevent two tasks from accessing the same resource (essentially competing for shared resources). One way to prevent such conflicts is to lock resources when they are used by a task. The first task to access a resource must lock it so that other tasks cannot access it until it is unlocked while another task can lock it and use it.

Synchronized is a synchronized lock:

  1. Any object can be used as a synchronization lock. All objects automatically have a single lock (monitor)
  2. Locking of synchronized methods: static methods (classname.class), non-static methods (this)
  3. Synchronized code block: self-specified, most often this or the class name.class

Note:

  1. It is important to ensure that multiple threads using the same resource share the same lock, otherwise the shared resource cannot be secured
  2. All static methods in a threaded class share the same lock (class name.class), all non-static methods share the same lock (this), synchronized code blocks (specify carefully)
  3. The synchronization method still refers to the synchronization monitor, but we don’t need to declare it explicitly.
  4. The non-static synchronization method, the synchronization monitor, is: this
  5. Static synchronization methods, the synchronization monitor is: the current class itself

4. Synchronization scope:

How do I find the problem, is the code thread-safe? (Very important)

(1) Specify which code is multithreaded code

(2) Determine whether multiple threads share data

(3) Determine whether there are multiple statements operating shared data in multi-threaded running code

How to solve it? (Very important)

When multiple operations share data, only one thread can complete the execution. During the execution, other threads cannot participate in the execution. That is, all of these statements that operate on shared data are placed in synchronization scope

Note:

Too small: not locking all code with security problems Too large: not using multithreading.

5. Interview questions:

1. Similarities and differences between synchronized and Lock?

  1. Same: Both address thread-safety issues

  2. Different: Synchronized automatically releases the synchronization monitor after executing the corresponding synchronization code

  3. Lock starts synchronization manually (Lock () and ends synchronization manually (unlock())

  4. Priority order of use:

    Lock– > Synchronize code block (already in method body, allocated resources) –> synchronize method (outside method body)

  5. Pros and cons: The synchronous approach solves the safety problem of threads. When synchronizing code, only one thread can participate, while the other threads wait. It’s a single-threaded process, which is inefficient.

2. How does Java address thread safety in several ways? And compare the differences of several ways

With synchronous locking, there are three ways to synchronize blocks of code, the synchronized method, and the lock method

3. Comparison between synchronized and Lock methods to solve thread safety problems

  1. Same: Both address thread-safety issues
  2. Different: Synchronized automatically releases the synchronization monitor after executing the corresponding synchronization code
  3. Lock starts synchronization manually (Lock () and ends synchronization manually (unlock())

6. Thread-safe singleton pattern

Use synchronization to rewrite the lazy from the singleton pattern to thread-safe.class Bank{

    private Bank(a){}

    private static Bank instance = null;

    public static Bank getInstance(a){
        // Method 1: less efficient
// synchronized (Bank.class) {
// if(instance == null){
//
// instance = new Bank();
/ /}
// return instance;
/ /}
        // Method 2: Be more efficient
        if(instance == null) {synchronized (Bank.class) {
                if(instance == null){

                    instance = newBank(); }}}returninstance; }}Copy the code

6. Deadlocks

  1. The understanding of deadlock: different threads occupy the synchronization resources needed by each other and do not give up. They are waiting for each other to give up the synchronization resources they need, and the thread deadlock is formed

  2. Description:

  • After a deadlock occurs, there are no exceptions, no hints, but all threads are blocked and cannot continue

  • When we use synchronization, we want to avoid deadlocks.

    Deadlock examples:

    public static void main(String[] args) {
    
        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();
    
    
        new Thread(){
            @Override
            public void run(a) {
    
                synchronized (s1){
    
                    s1.append("a");
                    s2.append("1");
    
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
    
                    synchronized (s2){
                        s1.append("b");
                        s2.append("2");
    
                        System.out.println(s1);
                        System.out.println(s2);
                    }
    
    
                }
    
            }
        }.start();
    
    
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                synchronized (s2){
    
                    s1.append("c");
                    s2.append("3");
    
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    synchronized (s1){
                        s1.append("d");
                        s2.append("4");
    
                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
    
    
    }
    
    Copy the code

5. Thread communication

In order to solve the thread deadlock problem, thread communication is introduced

1. Three methods involved in thread communication:

  • Wait (): Once this method is executed, the current thread blocks and releases the synchronization monitor.
  • Notify (): Once this method is executed, one of the threads being waited is awakened. If more than one thread is waited, the one with the highest priority is awakened.
  • NotifyAll (): Once this method is executed, all threads being waited are awakened.

2. Specification:

  • Wait (), notify(), and notifyAll() must be used in synchronized code blocks or synchronized methods.

  • The callers of wait(), notify(), and notifyAll() must be synchronized blocks or synchronization monitors in synchronized methods.

    Otherwise, there will be a IllegalMonitorStateException anomalies

  • Wait (), notify(), and notifyAll() are defined in the java.lang.object class.

Code examples:

Print 1-100 using two threads, thread 1 and thread 2 alternately.

class MyThread implements Runnable {
    private int number = 1;
    private Object object = new Object();

    @Override
    public void run(a) {
        while (true) {

            synchronized (object) {
                object.notify();// Call notify() to wake up the thread
                if (number <= 100) {
                    // Thread sleep
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + number);
                    number++;

                    try {
                        object.wait();// Call wait() to block the thread after printing the output once
                    } catch(InterruptedException e) { e.printStackTrace(); }}else {
                    break;
                }
            }
        }
    }
}

public class CommunicationTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();

        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);

        thread1.setName(Thread 1: "");
        thread2.setName(Thread 2: ""); thread1.start(); thread2.start(); }}Copy the code

3. Interview Questions:

What are the differences between sleep() and wait()?

Similarities: Once a method is executed, it can cause the current thread to block.

Difference:

Sleep (); Object (); wait()

2) Call requirements are different: Sleep () can be called in any scenario where it is needed. Wait () must be used in synchronized code blocks or synchronized methods

3) On whether to release the synchronization monitor: If both methods are used in synchronized code blocks or synchronized methods, sleep() does not release the lock, and wait() does.

4. Lock release operation:

  • The current thread’s synchronized method, synchronized code block completes execution
  • The current thread encounters a break or return in a synchronized code block or method that terminates the continuation of the method.
  • The current thread has an unhandled Error or Exception in a synchronized code block or method, resulting in an Exception ending.
  • The current thread executes the wait() method of the thread object in the synchronized code block, synchronized method, pauses and releases the lock

5. Operations that do not release locks:

  • When a Thread executes a synchronized code block or method, the program calls thread.sleep () and Thread yield() to suspend the execution of the current Thread
  • When a thread executes a block of synchronized code, it is suspended by another thread calling its suspend() method, and the lock is not released (synchronization monitor)
  • Use suspend() and resume() to control threads should be avoided whenever possible

JDK 5.0 new thread creation method

1. Added Method 1: Implement the Callable interface.

Implementation method:

  1. Create an implementation class that implements Callable

  2. Implement the call method to declare the actions this thread needs to perform in call()

  3. Create an object for the Callable interface implementation class

  4. The object of the FutureTask is created by passing the object of this Callable interface implementation class into the FutureTask constructor

  5. Pass the FutureTask object as an argument to the Thread constructor, create the Thread object, and call start()

  6. Gets the return value of the Call method in Callable

Code examples:

Create an implementation class that implements Callable
class NumThread implements Callable{
    //2. Implement the call method and declare the operation that this thread needs to perform in call()
    @Override
    public Object call(a) throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if(i % 2= =0){ System.out.println(i); sum += i; }}returnsum; }}public class ThreadNew {
    public static void main(String[] args) {
        //3. Create an object for the Callable interface implementation class
        NumThread numThread = new NumThread();
        //4. Pass the object of this Callable interface implementation class to the FutureTask constructor to create the Object of FutureTask
        FutureTask futureTask = new FutureTask(numThread);
        //5. Pass the FutureTask object as an argument to the Thread constructor, create the Thread object, and call start()
        new Thread(futureTask).start();

        try {
            //6. Get the return value of the call method in Callable
            The return value of get() is the return value of call() implemented by the FutureTask constructor Callable.
            Object sum = futureTask.get();
            System.out.println("The sum is:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch(ExecutionException e) { e.printStackTrace(); }}}Copy the code

How to understand the implementation of the Callable interface to create multiple threads is more powerful than the implementation of the Runnable interface to create multiple threads?

  1. Call () can return a value.
  2. Call () can throw an exception, which can be caught by an outside operation to get information about the exception
  3. Callable supports generics

2. Add method 2: Use a thread pool

Background: Heavily used resources that are frequently created and destroyed, such as threads in concurrent situations, have a significant impact on performance.

Solution:

Create several threads in advance, put them into the thread pool, get them directly when they are used, and put them back into the pool when they are used. It can avoid frequent creation and destruction and realize reuse. Similar to public transportation in life.

Implementation method:

  1. Provides a thread pool with a specified number of threads
  2. Performs operations for the specified thread. You need to provide objects that implement the Runnable or Callable interface implementation classes
  3. Disabling connection pooling

The API:

JDK 5.0Provide the thread pool related AP | : Executor Service and Executors Executor Service: real thread pool interface. Common subclassThread Poolexecutor
void executeRunnable <T> Future<T> submit (Callable<T>task) : Executes a task with a return value, and usually executes a Callablevoid shutdown(): Close connection pool Executors: Factory class for Tools and thread pools, used to create and return different types of thread pool Executors.newCachedThreadPool(a): Create a thread pool Executors for creating new threads on demand. NewF ⅸedthreadPool(n); Create a thread pool for reuse by fixed thread count EXecutors.newSingleThreadEXecutor(a): Create a thread pool with only one thread Executors. New ThreadPoo(n): Creates a thread pool that can schedule commands to run after a given delay or to execute them periodically.Copy the code

Code examples:

class NumberThread implements Runnable{

    @Override
    public void run(a) {
        for(int i = 0; i <=100; i++){if(i % 2= =0){
                System.out.println(Thread.currentThread().getName() + ":"+ i); }}}}class NumberThread1 implements Runnable{

    @Override
    public void run(a) {
        for(int i = 0; i <=100; i++){if(i % 2! =0){
                System.out.println(Thread.currentThread().getName() + ":"+ i); }}}}public class ThreadPool {

    public static void main(String[] args) {
        //1. Provide a thread pool with the specified number of threads
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
        // Set the properties of the thread pool
// System.out.println(service.getClass());
// service1.setCorePoolSize(15);
// service1.setKeepAliveTime();


        //2. Execute the operation of the specified thread. You need to provide objects that implement the Runnable or Callable interface implementation classes
        service.execute(new NumberThread());// Fit applies to Runnable
        service.execute(new NumberThread1());// Fit applies to Runnable

// service.submit(Callable callable); // Suitable for Callable
        //3. Disable the connection poolservice.shutdown(); }}Copy the code

The benefits of applying thread pools:

  1. Improved response times (reduced time to create new threads)

  2. Reduced resource consumption (reusing threads in the thread pool without creating them every time)

  3. Easy thread management

    CorePoolSize: Size of the core pool

    MaximumPoolSize: indicates the maximum number of threads

    KeepAliveTime: The maximum amount of time a thread can hold without a task before terminating

Interview question: How many ways can multithreading be created in Java? Four.

Before JDK 5.0:

  • That is, inheriting the Thread class to redo the run method
  • The Runnable interface implements the run method

After JDK 5.0:

  • Callable interface, call method
  • Leveraging thread pools