Multi-threaded learning route vomiting blood summary (including answers)

table of Contents

The concept of threads and processes

Why use multithreading?

What are the disadvantages of multithreading?

How to create threads?

Thread life cycle

When does the thread end?

How to realize instance variable sharing and non-sharing

Talk about the difference between sleep suspend wait

What is thread insecurity?

Examples of thread insecurity

Why call the start method will execute the run method

Can start be adjusted repeatedly?

What is the difference between calling the run method directly and calling the start method

How to understand join

How to communicate between threads?

Is volatile really useful?

ThreadLocal is used like this

Use of AtomicInteger

The difference between ThreadLocal and InheritableThreadLocal


The concept of threads and processes

When it comes to threads, one must say processes. Processes are the basic unit of system allocation and application. Processes can be understood as a program unit that can run independently, just like opening a QQ is a process (multiple QQs can be opened at the same time, allowing multiple processes? ), then a process can contain multiple threads. For example, opening a QQ chat window is one thread (if it is a chat merge window, there is only one thread).

Why use multithreading?

Using single thread, there will be a waiting situation when performing a long operation. Under the condition of multi-core CPU, in order to improve the utilization of the CPU, multiple threads can be used to perform other operations to reduce time-consuming.

What are the disadvantages of multithreading?

1. The use of multithreading consumes system resources, because multithreading needs to open up memory, and thread switching also takes time. (Multi-threaded processing leads to 80% of the production memory usage alarm)
2. The termination of the thread will affect the program.
3. There are shared data between multiple threads, which is prone to thread deadlock.

How to create threads?

//实现runnable接口  、继承 Thread,重写run方法、实现Callable

//1.runnable接口
public class MyThread  implements  Runnable{
    @Override
    public void run() {
        System.out.println("this is run");
    }

    public static void main(String[] args) {
        new Thread(new MyThread()).start();
    }
}
//2. 继承 Thread   缺点不能再继承了。
public class MyThread extends  Thread{
    @Override
    public void run() {
        System.out.println("this is run");
    }

    public static void main(String[] args) {
        new Thread(new MyThread()).start();
    }
}
//3.Callable   有返回值
public class ExcutorsCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "test";
    }
public static void main(String[] args) {
        MyThread task =new MyThread();
        FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
        Thread thread = new Thread(futureTask);
        thread.start();
  
 }
 }

Thread life cycle

Contains 5 stages, including: new, ready, running, blocking, and destroying.
New: the thread that has just used the new method and new comes out;
Ready: After the start() method of the called thread, the thread is in the stage of waiting for the CPU to allocate resources. Whoever grabs the CPU resources first will start the execution;
Run: When When a ready thread is scheduled and obtains CPU resources, it enters the running state. The run method defines the operation and function of the thread;
blocking: When in the running state, the thread in the running state may become blocked for some reason. For example, the thread is in a blocked state after sleep() and wait(). At this time, other mechanisms are needed to wake up the blocked thread, such as calling the notify or notifyAll() method. The awakened threads will not execute the run method immediately. They will wait for the CPU to allocate resources again and enter the running state;
destruction: If the thread is executed normally or the thread is forcibly terminated in advance or ends due to an abnormality, then the thread will be destroyed. Release resources;

When does the thread end?

1. The run method is executed normally 2. The run
method throws an exception
3. Return+interrupt 
4. Interrupt is generally not written in this way
during sleep 5. Stop does not recommend the JDK invalidation method

The run method throws an exception:

package com.demo.thread;

public class MyThread extends Thread {

    public MyThread(String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        if (true) {
            throw new RuntimeException("模拟业务异常");
        }
        System.out.println("run end");
    }

    public static void main(String[] args) {
        MyThread  myThread = new MyThread("t1");
        myThread.start();
    }
}
//可以看到后面 “run end” 不会执行了。

return+interrupt  


package com.demo.thread;

public class MyThread extends Thread {

    public MyThread(String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        while (true) {
            if(this.isInterrupted()){
                return;
            }
            System.out.println("run end");
        }
    }

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

//“run end” 就不会执行了

Interrupt is not a real stop, it is a stop mark, it is a thread interruption

interrupted Check whether the current thread is interrupted and clear the state. The second call is not interrupted.

isInterrupted Checks whether the current thread is interrupted, does not clear the state, and the second call is still interrupted.

How to realize instance variable sharing and non-sharing

Do not share:

package com.demo.thread;

public class TestVarShareThread extends Thread {
    private int count = 3;

    public TestVarShareThread(String name) {
        this.setName(name);
    }

    @Override
    public void run() {
        super.run();
        while (count > 0) {
            System.out.println(this.getName()+":"+count);
            count--;
        }
    }

    public static void main(String[] args) {
        TestVarShareThread t1 = new TestVarShareThread("t1");
        TestVarShareThread t2 = new TestVarShareThread("t2");
        TestVarShareThread t3 = new TestVarShareThread("t3");//这样创建不共享
        t1.start();
        t2.start();
        t3.start();
    }
}
t2:3
t2:2
t2:1
t3:3
t3:2
t3:1
t1:3
t1:2
t1:1

Sharing: (thread not safe)

public class TestVarShareThread extends Thread {
    private int count = 3;

    @Override
     public void run() {
        super.run();
        System.out.println(this.currentThread().getName() + ":" + count);
        count--;
    }

    public static void main(String[] args) {
        TestVarShareThread t = new TestVarShareThread();
        Thread t1 = new Thread(t, "t1");
        Thread t2 = new Thread(t, "t2");
        Thread t3 = new Thread(t, "t3");
        t1.start();
        t2.start();
        t3.start();
    }
t1:3
t2:3
t3:1

Improvement: lock

package com.demo.thread;

public class TestVarShareThread extends Thread {
    private int count = 3;

    @Override
    synchronized public void run() {
        super.run();
        System.out.println(this.currentThread().getName() + ":" + count);
        count--;
    }

    public static void main(String[] args) {
        TestVarShareThread t = new TestVarShareThread();
        Thread t1 = new Thread(t, "t1");
        Thread t2 = new Thread(t, "t2");
        Thread t3 = new Thread(t, "t3");
        t1.start();
        t2.start();
        t3.start();
    }
}

Talk about the difference between sleep suspend wait

Suspend is an outdated method, which is prone to deadlock and has not been used.

Sleep is the method of Thread. The current thread sleeps, and when the sleep time is up, it continues to run. Interrrupt for early operation

Wait is a method of the Object class, which makes the thread in a non-runnable state, and wake up with notify

Basically wait/notify is similar to sleep/interrupt, except that the former needs to acquire an object lock.

getId() Thread unique ID

What is thread insecurity?

When multiple threads operate on an instance variable in the same object, the value will be changed or the value will not be synchronized.

Examples of thread insecurity

package com.demo.thread;

public class ThreadTest {
    public static void main(String[] args) {
        TA t = new TA();
        int i = 0;
        while (i < 10) {
            new Thread(t).start();
            i++;
        }
    }
}

class TA implements Runnable {
    private int cnt =10;

    @Override
    public void run() {
        System.out.println(cnt);
        cnt = cnt - 1;
    }
}

10
9
8
8

6
5
4
3
2
1

If you change it, there will be no problem:

package com.demo.thread;

public class ThreadTest {
    public static void main(String[] args) {
      
        int i = 0;
        while (i < 10) {
                TA t = new TA();
            new Thread(t).start();
            i++;
        }
    }
}

class TA implements Runnable {
    private int cnt =10;

    @Override
    public void run() {
        System.out.println(cnt);
        cnt = cnt - 1;
    }
}

Why call the start method will execute the run method

Because the native method is called in the start, the native method is not implemented in Java, and the run method is called in other voice implementations.

Can start be adjusted repeatedly?

Can't. Exception in thread "main" java.lang.IllegalThreadStateException, and run can

What is the difference between calling the run method directly and calling the start method

Calling run directly is the same as calling a normal method. You have to wait for the run method to finish executing before continuing to execute, and start starts a thread to execute, without waiting, the program will continue to go down, and the content of the run method is independent of the thread. carried out.

How to understand join

The role of the t.join() method: the content after the main thread t.join() enters the waiting pool and waits for the t thread to finish executing before being awakened. It does not affect other threads that are running at the same time.

//开启3个线程
t1.start();
t2.start();
t1.join();
sysout("this is main");
t3.start();

T1 and t2 will be executed normally. When the main method runs to t1.join, the main method enters the waiting state, so "this is main" will not be printed, and the same t3.start() will not start. Wait for the end of t1. , Will continue to execute, print "this is main" and start t3. Note: The operation of t2 is not affected here, and the execution is still executed; and "this is main" and t3 will not be affected by t2, and will only wait for the end of t1.


package com.demo.thread;

public class JoinTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread("t1");
        MyThread t2 = new MyThread("t2");
        MyThread t3 = new MyThread("t3");
        System.out.println(1);
        t1.start();//睡3秒
        System.out.println(2);
        t2.start();//睡3秒
        t1.join();
        System.out.println(3);
        t3.start();//睡3秒
    }
}


package com.demo.thread;

public class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
                System.out.println(this.name+" start");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(this.name+" end");

    }
}

How to communicate between threads?

  The traditional way is to define an object with a List as its attribute, and then both threads refer to this list, one thread addlist, and the other thread judges the communication based on the size of the list. Disadvantages while occupies CPU resources

Via wait/notify

Is volatile really useful?

Function: Solve the memory invisibility and ensure that the value retrieved each time is the latest. (But, what's the use of this, I haven't used this keyword so far.)

My attempt: multi-threaded fetching increments, plus volatile can only ensure that the latest number is fetched each time, but it cannot guarantee that two threads will not get the same value. So volatile does not solve dirty reads. Iron FW? ? ? ?

private volatile int cnt = 0;
cnt++

ExecutorService service = Executors.newFixedThreadPool(3);
int i = 0;
while (i < 50) {
    service.execute(myThread);
 i++;
}

Eventually, two threads will get the same value, which is dirty read.

ThreadLocal is used like this


private static ThreadLocal<List<String>> listInstance= new ThreadLocal<List<String>>() {

    @Override

    protected List<String> initialValue() {

     return new ArrayList<>();

    }

};

listInstance.get().add("xxxx");

The data retrieved in this way are independent of each other.

ThreadLocal is also called thread local variable, that is, each thread copies a copy of the variable, so the threads do not interfere with each other.

Use of AtomicInteger

ThreadLocal is variable independence between threads, so if you want to share a variable, such as counting, how to do it?

private int cnt;

cnt++;

In this way, two threads will get the same value, dirty reading, or not thread-safe.

The correct approach is:

private AtomicInteger batchNum = new AtomicInteger(0);
batchNum.incrementAndGet();// batchNum.get()


This is thread-safe, and it is guaranteed that there will be no dirty reads.

to sum up

1. Multi-threaded shared variable count, use AtomicInteger.

2. Each thread uses variables independently, using ThreadLocal.

3. Don't use volatile indiscriminately.

The difference between ThreadLocal and InheritableThreadLocal

import com.demo.MyBean;

/**
 * 永久性测试类,可覆盖
 */
public class Test {
   private static ThreadLocal<MyBean> threadLocal = new ThreadLocal<>();
    private static InheritableThreadLocal<MyBean> threadLocal2 = new InheritableThreadLocal<MyBean>();
    public static void main(String[] args) {

        MyBean myBean = new MyBean();
        myBean.setName("22");
        threadLocal.set(myBean);
        threadLocal2.set(myBean);
        System.out.println(threadLocal.get());
        System.out.println(threadLocal2.get());
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(threadLocal.get());
                System.out.println(threadLocal2.get());
            }
        }).start();
    }
}

MyBean{id=0, name='22'}
MyBean{id=0, name='22'}
null
MyBean{id=0, name='22'}
InheritableThreadLocal 是ThreadLocal的子类,它的作用是父线程能给子线程传递值。用在父子线程共享变量的情况。

Guess you like

Origin blog.csdn.net/x18094/article/details/106086154