Let’s take a look at the question content first:
(Learning video sharing: java video tutorial)
public class TestSync2 implements Runnable { int b = 100; synchronized void m1() throws InterruptedException { b = 1000; Thread.sleep(500); //6 System.out.println("b=" + b); } synchronized void m2() throws InterruptedException { Thread.sleep(250); //5 b = 2000; } public static void main(String[] args) throws InterruptedException { TestSync2 tt = new TestSync2(); Thread t = new Thread(tt); //1 t.start(); //2 tt.m2(); //3 System.out.println("main thread b=" + tt.b); //4 } @Override public void run() { try { m1(); } catch (InterruptedException e) { e.printStackTrace(); } } }
The output of this program?
Program output results
main thread b=2000 b=1000 或 main thread b=1000 b=1000
Inspect knowledge points
synchronize instance lock.
Memory visibility under concurrency.
(Recommendations for more related interview questions: java interview questions and answers)
In Java, multi-threaded programs are the most difficult to understand and debug, and many times the execution results Didn't perform as well as we thought. Therefore, multi-threading in Java is particularly difficult. I vaguely remember that when I was taking the C language level 2 test in college, the questions in it were in line with many other priorities and asked about the final output result. For this type of question, I wanted to test some runtime operators. Issues of priority and integration. Just memorize it, but Java multi-threading still needs to be understood well, and memorizing it will not work.
Let’s start with a brief analysis:
This question involves 2 threads (main thread, sub-thread), and the keywords involve synchronized and Thread.sleep.
The synchronized keyword is still quite complicated (maybe sometimes it is not understood properly, so the above question will be a bit misunderstood). Its function is to achieve thread synchronization (there are many ways to achieve thread synchronization, it is just a method that will be discussed in subsequent articles). Yes, you need to study some implementations of the master Doug Lea). Its job is to lock the code that needs to be synchronized, so that only one thread can enter the synchronization block at a time (actually a pessimistic strategy) to ensure that the thread only remembers security. .
Usage of the general keyword synchronized
Specify the lock object: Lock the given object, and the lock of the given object needs to be activated before entering the synchronization code. Acting directly on the instance method: equivalent to locking the current instance. Before entering the synchronization code, you must obtain the lock of the current instance. Directly acting on static methods: equivalent to locking the current class. Before entering the synchronization code, the lock of the current class must be obtained.
The above code, synchronized usage actually belongs to the second situation. Acting directly on the instance method: equivalent to locking the current instance. Before entering the synchronization code, you must obtain the lock of the current instance.
Possible misunderstandings
Due to insufficient understanding of synchronized, many times, our multi-threads operate a synchronized method. When two threads call two different synchronized methods, It is a misunderstanding to think that there is no relationship when using methods. Acting directly on the instance method: equivalent to locking the current instance. Before entering the synchronization code, you must obtain the lock of the current instance. If one calls the synchronized method. It doesn't matter if the other one calls a normal method, and there is no waiting relationship between the two.
These are very useful for subsequent analysis.
Thread.sleep
Causes the current thread (that is, the thread that calls this method) to pause execution for a period of time to give other threads a chance to continue execution, but it does not release the object lock. That is to say, if there is a synchronized synchronization block, other threads still cannot access the shared data. Note that this method needs to catch exceptions, which is very useful for subsequent analysis. For some details, please refer to my System Learning Java High Concurrency Series 2.
Analysis process:
java is executed from the main method. As mentioned above, there are 2 threads, but it is useless to modify the thread priority here. The priority is in 2 programs. The order is only when they have not been executed. Now as soon as this code is executed, the main thread main has been executed. For the attribute variable int b =100, there will be no visibility problem due to the use of synchronized (there is no need to use volatile declaration), when executing step 1 (Thread t = new Thread(tt); //1) thread It is in the new state and has not started working yet.
When executing step 2 (t.start(); //2) when the start method is called, the thread is actually started and enters the runnable state. The runnable state indicates that it can be executed and everything is ready. , but it does not mean that it must be executed on the CPU. Whether it is actually executed depends on the scheduling of the service CPU. When executing step 3 here, you must first obtain the lock (because start needs to call the native method, and everything is ready after the use is completed, but it does not mean that it must be executed on the CPU. Whether it is actually executed depends on the scheduling of the service CPU. The run method will be called later and the m1 method will be executed).
It actually doesn’t matter whether Thread.sheep in the two synchronized methods is used or not. It is probably just to increase the difficulty of confusion. When step 3 is executed, the child thread is actually ready soon, but due to the existence of synchronized and the fact that it works on the same object, the child thread has to wait. Since the execution order in the main method is sequential, step 4 must be completed after step 3 is completed. Since step 3 is completed, the sub-thread can execute m1.
There is a problem here among multi-threads who gets it first. If it gets it first in step 4, then main thread b=2000. If sub-thread m1 gets it, b may have been assigned to 1000 or it will be output in step 4 before it has time to assign it. The possible result is main thread b=1000 or main thread b=2000. If step 6 is removed here, b= will be executed first and main thread b= first will be uncertain. But since the 6 steps exist, no matter what, the main thread b= is in the front, so it depends on the situation whether it is 1000 or 2000. After that, b=1000 is definitely fixed.
Some suggestions for multi-threading
Threads are also very precious, so it is recommended to use thread pools. Thread pools are used a lot. I will share them later. It is particularly important and you need to be aware of it. Give the thread a name. When the online CPU is high, you need to use advanced jstack. It will be much more convenient if there is a name. Multi-threading requires special attention to thread safety issues, and you also need to understand whether jdk is thread safe or unsafe, so that no inexplicable problems will occur when using it.
There are also some skills that will be shared in subsequent articles. Multi-threading is particularly important and difficult. I hope everyone will spend more time on it.
Some debugging skills for multi-threading
Due to breakpoints, all threads need to stop when passing the breakpoint, causing this point to be constantly interrupted, which is uncomfortable. There are Conditional breakpoints allow you to stop when the conditions are met, so this is convenient.
Related recommendations: java introductory tutorial
The above is the detailed content of I heard this is a difficult Java interview question?. For more information, please follow other related articles on the PHP Chinese website!