📅  最后修改于: 2023-12-03 14:58:31.544000             🧑  作者: Mango
这是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块中。
重构后的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 行 |