• 周六. 10 月 12th, 2024

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

【java_ Multithreading core problem

King Wang

1 月 3, 2022

1. start() Would call run() Method , Why do we still choose to use start() Method to open the thread

  • start() Methods call most of the time start0() Of native Method , It can start the life cycle of a thread correctly .
    run() Method is just a common method

2. A thread calls twice start() What happens to the method ? Why?

  1. It throws an exception
    The reason is that Thread t = new Thread() when The state of the thread is NEW
    Yes start() after , The thread will check the current thread state , If NEW Just run the thread , The thread state is changed to Runnable, When the second execution start() When the thread status is found Not for NEW Will throw an exception

3. How many ways to implement threads ?

  1. Make clear your position
    From a different point of view , There will be different answers
    I think it’s all implementation in essence Runnable And inheritance Thread
  2. Give me an example
    Thread pool Worker It’s essentially thread safe Runnable
    The core thread of the thread pool It’s using Thread.start() Open
    Support the return value of FutureTask It’s using Future One of the interface extensions Runnable
    Timing task TimerTask Also a Runnable

4. How to stop a thread

  1. use interrupt To request
    interrupt It’s not forcing the responder to respond immediately , It can participate in the business logic of the responder , Does not interrupt the responder’s original business logic , Ensure data security

  2. Use interrupt It needs cooperation -> Use api Or abnormal response
    2.1 Ordinary scenes
    Thread.interrupt + Thread.currentThread().isInterrupted()

    public static void main(String[] args) {
    
    Runnable runnable = new Runnable() {
    
    @Override
    public void run() {
    
    int i = 0;
    while (!Thread.currentThread().isInterrupted() && i < Integer.MAX_VALUE / 2) {
    
    if (i % 10000 == 0) {
    
    System.out.println(i);
    }
    i++;
    }
    }
    };
    Thread thread = new Thread(runnable);
    thread.start();
    try {
    
    Thread.sleep(2000); // zhege sleep Just let the thread run into the loop 
    } catch (InterruptedException e) {
    
    e.printStackTrace();
    }
    thread.interrupt();
    }
    

    2.2 with sleep() The situation of
    Capture exception

     try {
    
    int i = 0;
    while (!Thread.currentThread().isInterrupted() && i <= 300) {
    
    if (i % 100 == 0) {
    
    System.out.println(i);
    }
    i++;
    }
    Thread.sleep(1000); // sleep Outside the loop 
    } catch (InterruptedException e) {
    
    e.printStackTrace();
    }
    

    2.3 Every cycle sleep()
    Note that the interrupt flag will automatically clear after throwing an exception , Be careful try catch The scope of processing of

     try {
    
    int i = 0;
    while (!Thread.currentThread().isInterrupted() && i <= 300) {
    
    if (i % 100 == 0) {
    
    System.out.println(i);
    }
    i++;
    Thread.sleep(1000); // sleep Inside the loop 
    /*
    If try-catch Put it inside , Only one interrupt will be responded to , The next loop will reset the interrupt flag bit , If you want to use try-catch, And let the program respond to the interrupt and exit the loop , Need to use a big try Wrap the loop .
    */
    }
    } catch (InterruptedException e) {
    
    e.printStackTrace();
    }
    

    2.4 Best practices for interruptions in multi tier calls

    • Priority is given to throw interrupt exceptions , It’s forced on run Method
    • volite Can’t handle a long time blocking situation , It’s easy to fall into a hole
    • When the interrupt cannot be delivered , Prevent interrupts from being reset , Set the interrupt again
    • catch It was interrupted again + isInterrupted()
     @Override
    public void run() {
    
    while (true) {
    
    if (Thread.currentThread().isInterrupted()) {
    
    System.out.println(" The inner method has been broken , The outer method also needs to be interrupted , Out of the loop ");
    break;
    }
    System.out.println("go");
    reInterrupt();
    }
    }
    /**
    * In a child thread sleep() After the interruption , Then manually set the interrupt flag position to true
    *
    */
    private void reInterrupt() {
    
    try {
    
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    
    System.out.println(" Print log ");
    Thread.currentThread().interrupt();
    e.printStackTrace();
    }
    }
    
    1. Other blocks that can be interrupted
       Insert picture description here

5. How to deal with non interruptible blocking

unfortunately , There is no universal solution ,
But you can give two examples of scenarios :

  1. ReentrantLock.lockInterruptibly() Can respond to interruptions
  2. Inherit Thread rewrite interrupt()
    Handle IO Interruption of reading and writing

6. Six states of thread

  1. The twist of the State
     Insert picture description here
  2. A special case
     Insert picture description here

7. Handwritten producers, consumers

8. Alternate printing by program 0~100 Number of numbers

9. Why? wait() Need to be in sync block , and sleep Unwanted

  1. Code specification perspective :
    wait() Method and notify() It needs to be used together , Introduce synchronous code blocks to make notify() Strictly stay wait() After execution .
    Multithreading requires such a mandatory specification
  2. wait() The implementation of is lock level operation
    wait() Will release the caller’s lock , If not explicitly specified, it is this.wait(),
    Each object maintains a monitor Used to save lock information
    So in the synchronization code block, use lock.wait() Make all lock objects available wait(), Allow code to schedule with multiple locks wait() Method
    final static Object lock = new Object();
    sychronized(lock){
    
    lock.wait()
    }
    
  3. It can be used Thread.wait() Do you ?
    Do not use , It will cause hidden danger ,Thread At the time of design, we have completed an implementation , Thread execution completed , Automatic execution Thread.notify(),
    The execution time of a thread is uncontrollable , implicit Thread.notifyj() It can lead to unexpected results

10. notify() and notifyAll() The difference between

 Insert picture description here

11. join period , What state is the thread in

thread.join() The equivalent code of :

synchronized (thread) {

thread.wait(); // 
}

because thread Design time to achieve , Once the thread is finished , perform thead.notifyAll().
thread.join() It also implicitly realizes the main thread waiting thread The logic to run after it’s done
Main thread call thread.join() thread yes running state main yes waiting state

12. The difference between the guardian thread and the user thread

The guard thread serves the user thread ,JVM The program is terminated when no user thread is detected .
Even if there are Guardian threads , There is no user thread ,JVM You will think that there is no need for the guardian thread to exist

13. How to catch the exception thrown by the child thread in the main thread

  1. Realization Thread.UncaughtExceptionHandler Generate your own exception catcher
@Slf4j
public class MyUnCaughtExceptionHandler implements Thread.UncaughtExceptionHandler {

@Override
public void uncaughtException(Thread t, Throwable e) {

log.info("Thread : {}, thrown a Exception : {} ", t.getName(), e.getMessage());
}
}
  • Register your own exception catcher with the main thread
    Thread.setDefaultUncaughtExceptionHandler(new MyUnCaughtExceptionHandler());

  • Supplementary knowledge :
     Insert picture description here

14. The disadvantages of multithreading

Scheduling of threads

  • Context switch -> Lock competition 、 A lot of IO operation
    What is context switching ? Context is some register related operation of the operating system ,
    A context switch has the following activities :
    • Suspend a thread
    • Store the state of a thread somewhere in memory , The information stored is
      • Which instruction does the thread execute , Where is the position of the command
      • Program counter
  • Cache overhead
    CPU and There are multiple levels of cache between the memory to coordinate the speed difference , Caching is often used to improve the execution efficiency of applications , Such as for loop
    Frequent context switching can lead to cache invalidation

Thread collaboration

  • Memory synchronization
    volatile Prohibit command rearrangement , Let optimization fail
    Each thread may no longer maintain its own cache , To synchronize the main memory , Cost of access

发表回复