📜  门| GATE-CS-2017(Set 1)|第56章(1)

📅  最后修改于: 2023-12-03 14:58:31.544000             🧑  作者: Mango

GATE-CS-2017 (Set 1) 第56章

这是2021年的GATE-CS-2017 (Set 1) 入门题目。本题不仅考查了程序员对Java中Synchronized锁定的理解,还考察了线程同步、互斥和死锁的处理能力。

问题描述

考虑一下Java代码片段:

public class MyClass implements Runnable {
    static MyObject obj = new MyObject();

    public void run() {
        synchronized(obj) {
            for(int i=0; i<10; i++) {
                try {
                    Thread.sleep(1000);
                    System.out.print(Thread.currentThread().getName()+" ");
                } catch(InterruptedException e) { }
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyClass(), "t1");
        Thread t2 = new Thread(new MyClass(), "t2");
        t1.start();
        t2.start();
    }
}

问题是,MyClass的run方法运行时,所有线程都将执行10次“­t1|t2”的输出行。然而,在执行期间它们会同时停留在某个地方(由于线程同步错误),并永远不会继续。

要解决这个问题,需要修改MyClass的哪个部分?请描述一下,并解释问题的原因。

解题思路

这个代码使用了Synchronized关键字来锁定MyObject对象,目的是让线程在进入Synchronized块时互斥。然而,这里有一个明显的同步错误。如果一个线程进入了Synchronized块,并开始执行,但在释放锁之前被阻塞,那么另一个线程将无法进入该块,而且将一直等待,直到该线程释放了锁才能进行。

这种情况称为死锁。在这种情况下,两个或更多线程互相等待对方释放锁,因此它们都无法继续执行。由于本题中的Synchronized块包含了所有循环,因此它是导致死锁的原因。

解决这个问题的方法是确定产生死锁的原因,并消除它。在本题中,可以将Synchronized块放在for循环内,使线程在执行每个循环时都能释放锁。因此,正确的代码如下所示:

public class MyClass implements Runnable {
    static MyObject obj = new MyObject();

    public void run() {
        for(int i=0; i<10; i++) {
            synchronized(obj) {
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e) { }
                System.out.print(Thread.currentThread().getName()+" ");
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyClass(), "t1");
        Thread t2 = new Thread(new MyClass(), "t2");
        t1.start();
        t2.start();
    }
}

在新代码中,两个线程将交错地打印出“t1|t2”10次,并正确地互斥在Synchronized块中。

Markdown格式
代码片段

重构后的Java代码片段如下所示:

public class MyClass implements Runnable {
    static MyObject obj = new MyObject();

    public void run() {
        for(int i=0; i<10; i++) {
            synchronized(obj) {
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException e) { }
                System.out.print(Thread.currentThread().getName()+" ");
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyClass(), "t1");
        Thread t2 = new Thread(new MyClass(), "t2");
        t1.start();
        t2.start();
    }
}
表格

| 考察知识点 | Java中Synchronized锁定、线程同步、互斥和死锁处理 | | ---------------------- | --------------------------------------------------- | | 原始代码 | 见问题描述 | | 修正后的代码 | 见上面 代码片段 | | 导致死锁的原因 | Synchronized块包含所有循环 | | 死锁问题的解决方法 | 将Synchronized块放在每个循环内 | | 死锁问题解决后的输出 | t1奇数次打印、t2偶数次打印 | | 死锁问题解决后的代码量 | 1 行 |