📜  门| GATE 2017 MOCK II |问题25(1)

📅  最后修改于: 2023-12-03 15:28:36.546000             🧑  作者: Mango

门| GATE 2017 MOCK II |问题25

这个问题涉及到Java中的线程和同步。这是一个实战问题,将要求你分析给定的Java代码片段,并回答关于代码片段行为的一些问题。

代码片段
public class MyThread extends Thread {
    private static int i = 0;
    public synchronized void run() {
        for (; i<= 1000; i++) {
            System.out.print(i + " ");
        }
    }
}

class Main {
    public static void main(String args[]) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        t1.start();
        t2.start();
    }
}
代码行为

这个代码片段创建了两个线程(t1t2),这两个线程都是MyThread的实例。MyThread实现了Java的Thread类,并覆盖了run()方法,其中定义了一个同步块。

main()方法中,我们创建了两个MyThread的实例,并分别调用两个实例的start()方法,这将开启两个线程并开始执行run()方法。由于两个线程实例共享了静态变量i,因此两个线程都会将变量i从0增加到1000。

由于run()方法重写了synchronized方法,因此在一个线程正在运行synchronized块时,另一个线程将不能执行任何同步代码块。

问题
  1. 将同步关键字从run()方法移到for循环块上会发生什么?
  2. 如果我们将静态变量iMyThread类移到Main类中,并将它设置为volatile类型,会发生什么?
  3. 如果我们只针对静态变量i使用synchronized关键字,而不是在run()方法内使用,会发生什么?
回答
  1. 将同步关键字从run()方法移到for循环块上,将会导致同步块失去作用。这将允许两个线程同时运行,可能会发生竞态条件,从而导致不可预测的结果。
  2. 如果我们将静态变量iMyThread类移到Main类,并将它设置为volatile类型,那么每个线程都将从主存中读取变量的值。这将解决由于线程间缓存一致性问题导致的竞态条件。
  3. 如果我们只对静态变量i使用synchronized关键字,那么只有在访问i变量时才会进行同步。这将允许其他非同步代码块在两个线程的synchronized块之间运行。但是,在本例中,这不会对结果产生影响,因为synchronized块本身是在访问变量的时候运行的,因此这种情况下与原始代码片段的行为相同。