This is enough for the 2020 Java multithreaded interview questions, from thread creation to thread pool analysis (with answers)

Preface

A process refers to an application running in memory, and each process has its own independent piece of memory space, that is, process space or (virtual space). Processes do not depend on threads but exist independently, and multiple threads can be started in a process.
Thread refers to an execution flow in a process, and multiple threads can run in a process. A thread always belongs to a certain process. The thread does not have its own virtual address space. It shares all the resources allocated to the process with other threads in the process. The threads in the unified process share a heap memory, and each thread has its own stack memory. . The "simultaneous" execution is a human perception, and the execution is actually rotated between threads.

Synchronous and asynchronous

Synchronization: queued execution, inefficient but safe.
Asynchronous: synchronous execution, high efficiency but insecure data.

Concurrency and parallelism

Concurrency: Refers to two or more events occurring in the same time period.
Parallel: Two or more events occur at the same time (simultaneously).

3 ways of thread creation

1. Inheritance method

public  class MyThread extends Thread{
    @Override
    public void run(){
    }
}

        MyThread m = new MyThread();
        m.start();

2. Interface method

        //实现runnable
        //1 创建一个任务对象
        MyRunnable r = new MyRunnable();
        //创建一个线程并给他一个任务
        Thread t = new Thread(r);
        //启动线程
        t.start();

Advantages of the interface:

Compared with inheriting Thread, implementing Runnable has the following advantages:
1. Multi-threading is realized by creating tasks and then assigning tasks to threads, which is more suitable for the situation where multiple threads execute tasks at the same time.
2. It can avoid the limitations brought by single inheritance.
3. , Tasks and threads are separated, which improves the robustness of the program.
4. The thread pool technology learned later, accepts Runnable type tasks, but does not accept Thread type threads.

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("12345"+i);
                }
            }
        }.start();

But there is a very simple way of inheriting Thread. By rewriting run() by an anonymous internal class, multithreading is simply realized without creating a new class. Each thread has its own stack space and shares a heap memory.
A method called by a thread, and the method is executed in this thread.

3. Callable realizes the return of thread status (implements the Callalble interface)

The Callalble interface supports returning the execution result, which needs to be obtained by calling FutureTask.get(). This method will block the execution of the main process
, and it will not block if it is not called.

	Callable<Integer> callable= new MyCallable();
	FutureTask<Integer> future = new FutureTask<>(callable); 
	new Thread(future).start();
	Integer j=task.get();
	System.out.println("return"+j);

  1. Write a class to implement the Callable interface and implement the call method
class Mycallable implements Callable<T> { 
	@Override 
	public <T> call() throws Exception { 
	return T; 
	} 
} 

  1. Create a FutureTask object and pass in the Callable class object FutureTask written in the first step future = new FutureTask<>(callable);
  2. Through Thread, start the thread new Thread(future).start();

If the get method is called, the main thread waits for its execution to complete before executing. If it is not called, it has no effect on the main thread and can be parallelized.

FutureTask() method

Its parent Future() method

Daemon thread and user thread

Threads are divided into daemon threads and user threads.
User threads: when a process does not contain any surviving user threads, it ends.
Daemon threads: guarding user threads. When the last user thread ends, all daemon threads die automatically.
Java default thread is the user thread, and the daemon thread is set by calling setDaemon(true) on the thread.

        Thread t1 = new Thread(new MyRunnable());
        //设置守护线程
        t1.setDaemon(true);
        t1.start();

Three methods of thread synchronization

1. Synchronize the code block, specify the lock such as the same object

Format: synchronized (lock object){}

public class Demo8 {
    public static void main(String[] args) {
        Object o = new Object();
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable{
        //总票数
        private int count = 10;
        private Object o = new Object();
        @Override
        public void run() {
                while (true) {
                    synchronized (o) {
                        if (count > 0) {
                         //卖票
                            System.out.println("正在准备卖票");
                            try {
                            Thread.sleep(1000);
                            } catch (InterruptedException e) {
                            e.printStackTrace();
                            }
                            count--;
                            System.out.println(Thread.currentThread().getName()+"卖票结束,余票:" + count);
                        }else {
                            break;
                        }

                }
            }
        }
    }
}

2. Synchronization method

The synchronous method is called in run(). If it is a normal method, use this (this object) inside the method as the lock, if it is a static method, it is the class name.class (bytecode file object)

        public synchronized boolean test(){
                System.out.println("测试");
            }

3. Display lock

Both synchronization code blocks and synchronization methods are implicit locks.
Explicit locks are more intuitive, reflecting object-oriented, self-generating locks, and self-locking and unlocking.

    static class Test implements Runnable{
        //总票数
        //参数为true表示公平锁    默认是false 不是公平锁
        private Lock l = new ReentrantLock(true);
        @Override
        public void run() {
            l.lock();
            System.out.println("测试");
            l.unlock();
        }
    }

Fair lock and unfair lock

Fair lock: first come, first come, queue together.
Unfair lock: everyone grabs
Java by default, which is unfair lock. Fair lock can be realized through the construction method in explicit lock.

//设置公平锁
private Lock l= new ReentrantLock(true);

It is not fair if no parameter is passed, and false by default, but fair if passed in

Deadlock avoidance

In any method that may cause locks, do not call another method that may cause locks to generate another lock.
The following is an example of deadlock:

public class Demo11 {
    public static void main(String[] args) {
        //线程死锁
        Culprit c = new Culprit();
        Police p = new Police();
        new MyThread(c,p).start();
        c.say(p);
    }

    static class MyThread extends Thread{
        private Culprit c;
        private Police p;
        MyThread(Culprit c,Police p){
            this.c = c;
            this.p = p;
        }

        @Override
        public void run() {
            p.say(c);
        }
    }
    static class Culprit{
        public synchronized void say(Police p){//两方法公用this(此对象)锁,第一个方法不执行完无法执行第二个方法
            System.out.println("罪犯:你放了我,我放了人质");
            p.fun();
        }
        public synchronized void fun(){
            System.out.println("罪犯被放了,罪犯也放了人质");
        }
    }
    static class Police{
        public synchronized void say(Culprit c){
            System.out.println("警察:你放了人质,我放了你");
            c.fun();
        }
        public synchronized void fun(){
            System.out.println("警察救了人质,但是罪犯跑了");
        }
    }
}

Deadlock

If the first thread executes (assumed) p.fun(), the second thread p has not executed the p.say() method, and the lock is not reached at this time. Both methods can be executed, but an error occurs.

Producer and consumer

1. A class can be modified and read. If thread synchronization is not used, a read operation by another thread occurs during modification, and dirty data will be read.
2. By adding the synchronized thread synchronization method, the problem of reading dirty data can be solved by not being able to read during modification, but the synchronization between the two threads cannot be achieved, and the phenomenon of preempting the time slice of one thread cannot be synchronized.
3. If you want to read and modify can wait for synchronization with each other, you also need to add wait and notify operations. One will rest after executing notifyall and set the identification flag, and the other will read the identification flag and execute it after being awakened, then rest, waking up the other. Add the flag flag to determine the order of thread execution.

package com.java.demo;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo4  {

    /**
     * 多线程通信问题, 生产者与消费者问题
     * @param args
     */
    public static void main(String[] args) {
        Food f = new Food();
        new Cook(f).start();
        new Waiter(f).start();
    }

    //厨师
    static class Cook extends Thread{
        private Food f;
        public Cook(Food f) {
            this.f = f;
        }

        @Override
        public void run() {
            for(int i=0;i<100;i++){
                if(i%2==0){
                    f.setNameAndSaste("老干妈小米粥","香辣味");
                }else{
                    f.setNameAndSaste("煎饼果子","甜辣味");
                }
            }
        }
    }
    //服务生
    static class Waiter extends Thread{
        private Food f;
        public Waiter(Food f) {
            this.f = f;
        }
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                f.get();
            }
        }
    }
    //食物
    static class Food{
        private String name;
        private String taste;

        //true 表示可以生产
        private boolean flag = true;

        public synchronized void setNameAndSaste(String name,String taste){
            if(flag) {
                this.name = name;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.taste = taste;
                flag = false;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public synchronized void get(){
            if(!flag) {
                System.out.println("服务员端走的菜的名称是:" + name + ",味道:" + taste);
                flag = true;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Thread status

Thread state. A thread can be in one of the following states: A thread that has not been started by
NEW is
in this state.
RUNNABLE
The thread executed in the Java virtual machine is in this state.
BLOCKED
is blocked waiting for the monitor lock thread in this state.
WAITING
indefinitely waiting for another thread to perform a specific operation thread in this state.
TIMED_WAITING A
thread that is waiting for another thread to perform operations up to the specified waiting time is in this state.
TERMINATED
exited threads are in this state.
A thread can only be in one state at a given point in time. These states are virtual machine states and do not reflect any operating system thread state.

Thread Pool

1. Cache thread pool

Unlimited length
The execution process after the task is added:
1. Determine whether there is an idle thread in the thread pool
2. If it exists, use it
3. If it does not exist, create a thread and use it


        ExecutorService service = Executors.newCachedThreadPool();
        //指挥线程池执行新的任务
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"测试");
            }

        });

2. Fixed-length thread pool

The length is the specified thread pool
. The execution flow after joining the task:
1 Determine whether there is an idle thread in the thread pool
2 If it exists, use
3 If there is no idle thread and the thread pool is not full, create a thread and put it in the thread pool and use
4 If there is no idle thread and the thread pool is full, wait for the idle thread of the thread pool

		//设置定长线程池
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"测试");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });

3. Single threaded thread pool

The effect is the same as a fixed-length thread pool with a length of 1.
Execution process
1 Determine whether the thread in the thread pool is idle
2 If it is idle, use it
3 If it is not idle, wait for it to be idle before using it

        ExecutorService service = Executors.newSingleThreadExecutor();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"测试");
            }
        });

4. Period fixed-length thread pool

执行流程
    1 判断线程池是否存在空闲线程
    2 存在则使用
    3 不存在空闲线程  且线程池未满的情况下  则创建线程  并放入线程池中  然后使用
    4 不存在空闲线程  且线程池已满的情况下  则等待线程池的空闲线程

Periodic task execution:
execute a certain task automatically when a certain task is triggered

Execute once:

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
        //定时执行一次
        //参数1:定时执行的任务
        //参数2:时长数字
        //参数3:2的时间单位    Timeunit的常量指定
       	scheduledExecutorService.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"测试");
            }
        },5, TimeUnit.SECONDS);      //5秒钟后执行*/

Periodic execution

        周期性执行任务
            参数1:任务
            参数2:延迟时长数字(第一次在执行上面时间以后)
            参数3:周期时长数字(没隔多久执行一次)
            参数4:时长数字的单位
        * **/
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"测试");
            }
        },5,1,TimeUnit.SECONDS);

Lambda expression

When using anonymous inner classes as parameters, you can use lambda notation to greatly simplify the code.

        //冗余的Runnable编写方式
       Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("测试");
            }
        });
        t.start();

Keep the passed parameters, keep the method body to be rewritten, use -> connect in the middle

        Thread t = new Thread(() -> System.out.println("测试"));

to sum up

Finally, I prepared the Java architecture learning materials for everyone. The learning technology content includes: Spring, Dubbo, MyBatis, RPC, source code analysis, high concurrency, high performance, distributed, performance optimization, microservice advanced architecture development, etc. Friends in need click here to remark csdn and download by yourself ! Another reminder, full review is the key to eliminating your nervous state of mind, but if you review enough, you will naturally have more confidence in the interview process.

Guess you like

Origin blog.csdn.net/jiagouwgm/article/details/111676667