下面是一段有关Java线程的题目。
以下是一个Java类的代码:
1 public class Test {
2
3 int a=0;
4 int b=0;
5 int x=0;
6 int y=0;
7
8 public static void main(String[] args) throws InterruptedException {
9 Test test = new Test();
10 test.run();
11 }
12
13 private void run() throws InterruptedException{
14 Thread th1 = new Thread(){
15 public void run(){
16 a = 1;
17 y = b;
18 }
19 };
20 th1.start();
21
22 Thread th2 = new Thread(){
23 public void run(){
24 b = 1;
25 x = a;
26 }
27 };
28 th2.start();
29
30 th1.join();
31 th2.join();
32
33 System.out.println("x = " + x + ", y = " + y);
34 }
35 }
2
3 int a=0;
4 int b=0;
5 int x=0;
6 int y=0;
7
8 public static void main(String[] args) throws InterruptedException {
9 Test test = new Test();
10 test.run();
11 }
12
13 private void run() throws InterruptedException{
14 Thread th1 = new Thread(){
15 public void run(){
16 a = 1;
17 y = b;
18 }
19 };
20 th1.start();
21
22 Thread th2 = new Thread(){
23 public void run(){
24 b = 1;
25 x = a;
26 }
27 };
28 th2.start();
29
30 th1.join();
31 th2.join();
32
33 System.out.println("x = " + x + ", y = " + y);
34 }
35 }
运行后输出的结果是【 】
A. x = 0, y = 0 B. x = 0, y = 1 C. x = 1, y = 0 D. x = 1, y = 1
对于这道题目,答案可能会出现多种:
a)对线程没有任何了解的人,给出的答案应该是C;
b)对线程有了解的人,根据不同的理解程度,会给出的答案应该是B、C、D中的任意两个的组合或者三个全部选择上;
c)对线程和JVM运行机制都有了解的人,答案只有一个ABCD。
可能很多童鞋会有疑问了,为什么会出现A呢???
我写了一段代码来连续运行了1000W次,出现ABCD的次数如下:
A: 13, B: 240662, C: 9759320, D: 5
下面我就来解释下为什么会出现以上各种可能(按照难易程度逐个解释):
C. 这个最简单,在这里就不多解释了,JVM按照代码的先后顺序执行就是这个结果。
B. 这里先解释下start这个方法。当程序调用start方法的时候,JVM会创建一个新的线程,在这时会调用线程内部的init方法。init方法会先由SecurityManager决定档期那线程执行哪些操作,没有则由当前线程取得对应的ThreadGroup线程树(其中已有主线程),然后init方法贩毒案它是否为守护线程,得到线程的优先级以及内部自动生成的nextThreadID和出示的stackSize。做完这些之后,当前线程处于就绪状态,这是将会有两个线程开始执行:一个是主线程,一个是主线程调用start方法创建的线程。新创建的线程会添加到ThreadGroup中,这时CPU会根据当前线程的优先级,通过时间片流转执行当前线程,时间片轮状的时间很短,所以感觉上是马上执行。
所以在上面的代码中尽管线程th1在th2之前声明和调用start方法,但是由于线程优先级,有可能th2线程在th1线程之前运行,这样就执行后的结果就是B了。
D. 当线程th1运行完第16行之后,由于CPU调度资源竞争等原因,可能接下来运行的就是线程th2,当运行完第24行后又去运行第17行代码,这样一来就会出现D的结果了。
A. 对于A这个结果其实很多人都不解,其实原因说起来很简单。因为JVM在执行编译后的java代码时,在一个代码块中,如果改变执行顺序后不影响最终的结果,JVM不一定会按照代码顺序执行那段代码,也就是说第16行和第17行的代码,第24行和第25行代码的执行顺序有可能是颠倒的。然后参考D的解释就可以得到A这个答案了。
到此结束,如果有哪里解释的不对,请拍砖,随时欢迎。
来源:《Java并发编程实践》。