Java Road to God: Java Interview Preparation (9)

5. Multithreading

5.1 The results of running the following program

public static void main(String[] args) {
    
    
     Thread t=new Thread(){
    
    
          public void run(){
    
    
          pong();
     }
}
t.run();
System.out.println("ping");
}
static void pong(){
    
    
      System.out.println("pong");
}

5.2 Which of the following methods can be used to create a runnable class

5.3 Explain the function and principle of java.lang.ThreadLocal. List in which programs have seen the use of ThreadLocal

effect:

It is difficult to write a multi-thread safe (Thread-safe) program. In order to allow threads to share resources, the shared resources must be carefully synchronized. Synchronization brings a certain performance delay. On the other hand, when processing synchronization , And pay attention to the locking and release of objects to avoid deadlocks. Various factors make it difficult to write multi-threaded programs.

Try to think about the problem of multi-threaded sharing resources from another angle. Since sharing resources is so difficult, then just don't share them at all, why not create a copy of resources for each thread. The behavior of each thread's access to data is isolated, and the way to achieve this is to give each thread a specific space to keep the resources exclusive to that thread.

For example: Session in Hibernate is used.

The principle of ThreadLocal

How does ThreadLocal maintain a copy of the variables for each thread? In fact, the idea of ​​implementation is very simple. There is a Map in the ThreadLocal class, which is used to store a copy of the variables of each thread.

5.4 Talk about optimistic locking and pessimistic locking

Pessimistic Lock (Pessimistic Lock), as the name suggests, is very pessimistic. Every time you get the data, you think that others will modify it, so every time you get the data, you will lock it, so that if someone wants to get the data, it will block until it gets it. To the lock. Many such locking mechanisms are used in traditional relational databases, such as row locks, table locks, etc., read locks, write locks, etc., which are all locked before operations.

Optimistic Lock (Optimistic Lock), as the name suggests, is very optimistic. Every time I go to get data, I think that others will not modify it, so it will not be locked, but when updating, it will judge whether others have updated this during this period. For data, mechanisms such as version numbers can be used. Optimistic locking is suitable for multi-read application types, which can improve throughput. If the database provides a mechanism similar to write_condition, it is actually optimistic locking.

Both types of locks have their own advantages and disadvantages. One should not be considered better than the other. For example, optimistic locks are suitable for less writes, that is, when conflicts really rarely occur, which saves the overhead of locks. Increase the overall throughput of the system. However, if conflicts occur frequently, the upper-level application will continue to retry, which will actually reduce the performance, so in this case it is more appropriate to use pessimistic locks.

5.5 How to implement multithreading in Java? Describe the changing process of thread state

When multiple threads access the same data, thread safety issues are prone to occur, and some way is needed to ensure that resources are only used by one thread at a time. Need to synchronize threads to ensure data safety. The implementation of thread synchronization: synchronization code blocks and synchronization methods, both need to use the synchronized keyword

Synchronization code block: public void makeWithdrawal(int amt) {

synchronized (acct) { }

}

Synchronization method: public synchronized void makeWithdrawal(int amt) {}

The benefits of thread synchronization: solve the thread safety problem

Disadvantages of thread synchronization: performance degradation may lead to deadlock

5.6 Please write multi-threaded code using Thread or Runnable, and tell the difference between the two.

Method 1: Inherit the Java.lang.Thread class and override the run() method. Advantages: simple to write; disadvantages: unable to inherit from other parent classes

public class ThreadDemo1 {
    
    
public static void main(String args[]) {
    
    
MyThread1 t = new MyThread1();
t.start();
while (true) {
    
    
System.out.println("兔子领先了,别骄傲");
}
}
}
class MyThread1 extends Thread {
    
    
public void run() {
    
    
while (true) {
    
    
System.out.println("乌龟领先了,加油");
}
}
}

Method 2: Implement the Java.lang.Runnable interface and implement the run() method. Advantages: other classes can be inherited, multiple threads can share the same Thread object; disadvantages: the programming method is slightly more complicated, if you need to access the current thread, you need to call the Thread.currentThread() method

public class ThreadDemo2 {
    
    
public static void main(String args[]) {
    
    
MyThread2 mt = new MyThread2();
Thread t = new Thread(mt);
t.start();
while (true) {
    
    
System.out.println("兔子领先了,加油");
}
}
}
class MyThread2 implements Runnable {
    
    
public void run() {
    
    
while (true) {
    
    
System.out.println("乌龟超过了,再接再厉");
}
}
}

5.7 What is the calling method of the wait method in multithreaded programming?

The wait method is one of the methods of thread communication. It must be used in the synchronized method or synchronized code block, otherwise an exception will be thrown. This involves the concept of a "lock", and the wait method must be called using the locked object. Thus, the lock holding the object enters the thread waiting state, until the notify or notifyAll method is called using the locked object to wake up the waiting thread to release the held lock.

5.8 Several states of Java thread

Six states of threads

  • Initial state
    A thread class can be obtained by implementing the Runnable interface and inheriting from Thread. When a new instance comes out, the thread enters the initial state.

  • Ready state
    Ready state just means that you are qualified to run. If the scheduler does not pick you up, you will always be in ready state.
    The start() method of the thread is called, and the thread enters the ready state.
    The sleep() method of the current thread ends, and the join() of other threads ends, waiting for the user's input to be completed, and a thread gets the object lock, and these threads will also enter the ready state.
    The current thread time slice is used up, call the yield() method of the current thread, and the current thread enters the ready state.
    After the thread in the lock pool gets the object lock, it enters the ready state.
    Running state The state of the
    thread when the thread scheduler selects a thread from the runnable pool as the current thread. This is also the only way for a thread to enter the running state.

  • Blocking state The
    blocking state is the state when the thread is blocked when it enters the method or code block modified by the synchronized keyword (acquisition of the lock).

  • Waiting
    . Threads in this state will not be allocated CPU execution time. They have to wait to be explicitly awakened, otherwise they will wait indefinitely.

  • Overtime waiting
    . Threads in this state will not be allocated CPU execution time, but there is no need to wait indefinitely to be awakened by other threads. They will automatically wake up after a certain amount of time is reached.

  • Termination state
    When the thread's run() method completes, or the main thread's main() method completes, we consider it terminated. This thread object may be alive, but it is no longer a separate thread of execution. Once the thread is terminated, it cannot be reborn.
    Calling the start() method on a terminated thread will throw a java.lang.IllegalThreadStateException.

  • Waiting queue
    Before calling the wait(), notify() methods of obj, the obj lock must be acquired, that is, it must be written in the synchronized(obj) code segment.

5.9 In Java multithreading, which of the following methods will not cause the thread to enter the blocking state

Insert picture description here

5.10 Does the volatile keyword guarantee thread safety?

Can't. Although volatile provides a synchronization mechanism, knowledge is a weak synchronization mechanism. If you need strong thread safety, you also need to use synchronized.

The Java language provides a weaker synchronization mechanism, namely volatile variables, to ensure that the update operation of the variable is notified to other threads. When a variable is declared as a volatile type, the compiler and runtime will notice that the variable is shared, so the operations on the variable will not be reordered with other memory operations. Volatile variables will not be cached in registers or invisible to other processors, so when reading a volatile variable, the latest written value will always be returned.

1. The memory semantics of volatile are:

When writing a volatile variable, JMM will immediately flush the shared variable value in the local memory corresponding to the thread to the main memory.

When reading a volatile variable, JMM will invalidate the local memory corresponding to the thread and read the shared variable directly from the main memory.

Second, the implementation mechanism of volatile bottom layer

If you generate assembly code for the code with the volatile keyword and the code without the volatile keyword, you will find that the code with the volatile keyword will have an extra lock prefix instruction.

1. When reordering, the following instructions cannot be reordered to the position before the memory barrier

2. Make the Cache of the CPU write to the memory

3. The write action will also cause other CPUs or other cores to invalidate its Cache, which is equivalent to making the newly written value visible to other threads.

5.11 Please write down the commonly used Java multi-threaded startup methods. There are several commonly used types of Executors thread pools

(1) Inherit the Thread class

public class java_thread extends Thread{
    
    
    public static void main(String args[]) {
    
    
        new java_thread().run();
        System.out.println("main thread run ");
    }
    public synchronized  void run() {
    
    
        System.out.println("sub thread run ");
    }
}

(2) Implement the Runnable interface

public class java_thread implements Runnable{
    
    
    public static void main(String args[]) {
    
    
        new Thread(new java_thread()).start();
        System.out.println("main thread run ");
    }
    public void run() {
    
    
        System.out.println("sub thread run ");
    }
}

Under the Executor framework, three types of commonly used thread pools can be created using the static method of Executors:

1) FixedThreadPool This thread pool can create a thread pool with a fixed number of threads.

2) SingleThreadExecutor is an Executor that uses a single worker thread.

3) CachedThreadPool is a thread pool with "unlimited" capacity, it will create new threads as needed.

5.12 Regarding sleep**() and wait(), one of the following descriptions of errors is **

5.13 What is the difference between process and thread

A process is a running activity of a program with a certain independent function on a certain data set, and a process is an independent unit of the system for resource allocation and scheduling.

A thread is an entity of a process and the basic unit of CPU scheduling and dispatch. It is a basic unit that is smaller than a process and can run independently. The thread itself basically does not own system resources, only a few resources that are essential in operation (Such as the program counter, a set of registers and stack), but it can share all the resources owned by the process with other threads belonging to the same process.

5.14 Create n multiple threads, how to ensure that these threads start at the same time? See clearly, it's "at the same time"

Use a for loop to create a thread object, and call the wait() method at the same time to make all threads wait; until the last thread is also ready, call notifyAll() to start all threads at the same time.

For example: Give you n cars and let them all start on the starting line at the same time. How to write code in Java multi-threading?

The idea is to add a lock to a car and modify the corresponding operands. If not everything is ready, wait and release the lock until the last car arrives to wake up all racing threads. The code reference is as follows

public class CarCompetion {
    
    
    // 参赛赛车的数量
    protected final int totalCarNum = 10;
    // 当前在起跑线的赛车数量
    protected int nowCarNum = 0;
}
public class Car implements Runnable{
    
    
    private int carNum;
    private CarCompetion competion = null;
    public Car(int carNum, CarCompetion competion) {
    
    
        this.carNum = carNum;
        this.competion = competion;
    }
    @Override
    public void run() {
    
    
        synchronized (competion) {
    
    
            competion.nowCarNum++;
            while (competion.nowCarNum < competion.totalCarNum) {
    
    
                try {
    
    
                    competion.wait();
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            competion.notifyAll();
        }
        startCar();
    }
    private void startCar() {
    
    
        System.out.println("Car num " + this.carNum + " start to run.");
        try {
    
    
            Thread.sleep(3000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        System.out.println("Car num " + this.carNum + " get to the finish line.");
    }
}
public static void main(String[] args) {
    
    
    CarCompetion carCompetion = new CarCompetion();
    final ExecutorService carPool =
        Executors.newFixedThreadPool(carCompetion.totalCarNum);
    for (int i = 0; i < carCompetion.totalCarNum; i++) {
    
    
        carPool.execute(new Car(i, carCompetion));
 
}

5.15 How do threads communicate

1. Synchronization, which is our commonly used synchronized keyword. This method is essentially a shared variable. Whoever gets the lock first will execute it first.

2. The while loop. This is also implemented based on shared memory, and is generally used in conjunction with the volatile keyword. In a multi-threaded environment, we use the while loop to make judgments to prevent false wakeups

3. The notify/wait method.

Guess you like

Origin blog.csdn.net/weixin_54707168/article/details/113975387