Daily back-end interview 5 questions the third day

  1. What are the states of threads and the transitions between them? (must)

Look at the picture:

A thread has 4 states in total, namely:

1. Creation/new state new: It has been new, but has not yet started().

2. Ready state runable: start(), and will grab the cpu later.

  Grabbing the cpu is the legendary fifth state of running. (the agreed 5 types)

  The sixth running state runs the code in run().

3. Blocked state: Run the run halfway through the run, get angry and stop running, and wait until the conditions are quite sufficient and the mood is good before running.

   There are three cases:

1) Waiting for waiting: play with wait()

2) Time waiting time waiting: sleep () or join () or issued an I/O request.

3) Blocking blocked: locked by synchronized

4. Death state terminated: the code in run is finished, and it dies

Supplement: The difference between the start and run methods

1. In terms of type, start is a synchronous method, and run is an asynchronous method. 

2. In terms of function, the run method stores the task code, and the start method starts the thread thread

3. In terms of the impact on the number of threads, run will not generate new threads, but start will generate new threads

4. In terms of the number of calls, the run method can be executed countless times, while the star method can only be executed once, because the thread cannot be started repeatedly

Combining 2 and 3 points can answer:

Addition: Briefly describe the difference between the start method and the run method of running threads in the main method, please see the question:

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        Thread t0 = new MyThread();
        Thread t1 = new MyThread();

        Thread t2 = new MyThread();
        Thread t3 = new MyThread();

        t0.start();
        t1.start();

        System.out.println("=================================");

        t2.run();
        t3.run();
    }
}

What is the result of running the above code?

A.

thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
... // t0和t1交替运行,打印0到99
thread-0 99
thread-1 99
=================================
thread-2 0 // t2.run()启动
thread-2 1
thread-3 0 // t3.run()启动
thread-3 1
... // t2run和t3run交替运行,打印0到99
thread-3 99
thread-2 99

 B.

=================================
thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
main 0 // t2.run()启动
main 1
... // t0、t1和t2run交替运行,打印0到99
thread-0 99
thread-1 99
main 99
main 0 // t3.run()启动
main 1
... // t3run运行,打印0到99
main 99

 C.

thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
... // t0和t1交替运行,打印0到99
thread-0 99
thread-1 99
=================================
main 0 // t2.run()启动
main 1
... // t2run运行,打印0到99
main 99
main 0 // t3.run()启动
main 1
... // t3run运行,打印0到99
main 99

D.

=================================
thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
main 0 // t2.run()启动
main 1
main 0 // t3.run()启动
main 1
... // t0、t1和t2run、t3run交替运行,打印0到99
thread-1 99
main 99
main 99
thread-0 99

 The answer is B. The reason needs to be understood in combination with points 2 and 3 above.

2. In terms of function, the run method stores the task code, and the start method starts the thread thread

3. In terms of the impact on the number of threads, run will not generate new threads, but start will generate new threads

More to add: Variation questions

class MyThread extends Thread {
    @Override
    public void run() {
        synchronized (this) {  // 注意这里加了个线程锁
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        Thread t0 = new MyThread();
        Thread t1 = new MyThread();

        Thread t2 = new MyThread();
        Thread t3 = new MyThread();

        t0.start();
        t1.start();

        System.out.println("=================================");

        t0.run();  // 注意这里改成t0了
        t3.run();
    }
}

What is the result? Comment out the equal sign that prints the separator:

public class TestThread2 {
    public static void main(String[] args) {
        Thread t0 = new MyThread();
        Thread t1 = new MyThread();

        Thread t2 = new MyThread();
        Thread t3 = new MyThread();

        t0.start();
        t1.start();
//        注意注释掉了打印等号分隔
//        System.out.println("=================================");

        t0.run();  // 注意这里改成t0了
        t3.run();
    }
}

More to add: Variation Variations

code show as below:

public class MyRun implements Runnable {
    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        MyRun myRun = new MyRun();
        Thread thread0 = new Thread(myRun);
        Thread thread1 = new Thread(myRun);

        thread0.start();
        thread1.start();

        System.out.println("=================================");

        thread0.run();
    }
}

2. What is the singleton pattern? How many kinds are there?

There are 5 singleton patterns:

1. Eager Initialization

Created when the class is loaded.

Advantages: simple implementation, thread safety, no multi-threading problems;

Disadvantage: If the instance is not used, resources will be wasted.

2. Lazy Initialization

Created for first use.

Advantages: Lazy instantiation saves resources.

Disadvantages: thread unsafe.

3. Double-Checked Locking

Lazy style plus synchronization lock.

Advantages: thread safety.

Disadvantages: The implementation is relatively complex, and there may be problems with some compilers and instruction reordering.

4. Static Inner Class

Placed in a static inner class, thread safety is guaranteed when the class is loaded.

Advantages: thread safe and does not rely on synchronization locks.

Disadvantages: The implementation is relatively complicated, and it is necessary to understand the characteristics of static inner classes.

5. Enumeration (Enum)

Use the enumeration class to create and save singleton instances.

Advantages: simple to implement, thread-safe, and can prevent reflection and serialization from destroying singletons.

Disadvantages: Not flexible enough to delay instantiation.

The detailed description of the creation of Hungry Man was added.

Lazy man's creation details description added.

The difference between hungry man plus static code block, lazy man plus synchronization method, study this article and add:

Eight Types of Singleton Patterns - There Are Several Types of Singletons - Despicable Me Blog

3. The difference between List and Map and Set

Collection storage is essentially different:

List and Set are single-column collections that store one type of data; Map is a double-column collection that stores key-value pair data.

The internal storage rules of collections are different:

The data in the List is ordered and can be repeated;

The data in the Set is unordered and cannot be repeated;

The data in the Map is unordered, the key cannot be repeated, and the value can be repeated.

Further analysis on the position in Set

The position in the Set is fixed, but there is no order, and it is still unordered.

The position of the element in the Set is determined by the hashcode, and this is fixed. But this is beyond the control of the user, so it is still disordered.

4. When using the HashMap collection to store data, under what circumstances will hash conflicts occur?

When the calculated hashcode, that is, the hash value is the same, a hash conflict will occur.

5. What is the difference between Runnable and Callable?

Back on:

Runnable has no return value; Callable has a return value.

On exception handling:

Runnable can only throw runtime exceptions and cannot be caught and processed; Callable allows exceptions to be thrown and exception information can be obtained.

Guess you like

Origin blog.csdn.net/m0_46948660/article/details/132148293
Recommended