假设以下课程
public class TestObject{
public void synchronized method1(){
//some 1000 lines of code
}
public void method2(){
//some 1000 lines of code
}
}
假设有两个线程访问相同的TestObject类实例,让我们称它们为t1和t2。我想知道在下面的场景中会发生什么。
我的理解是,对于第一个问题,线程t2将不被授予权限,因为对象将被t1锁定。对于第二个问题,线程t2将被授予访问权并锁定对象并将t1从执行中停止。但我的假设是错误的。有谁能解释一下?
由于
答案 0 :(得分:8)
当线程在该方法中运行时,只有带关键字synchronized的方法才会锁定此对象。
如果方法1和方法2都被声明为同步,则即使他们尝试运行不同的方法,一个线程也会阻止另一个线程。
在您的示例中,只有1个方法被隐式锁阻塞
结果,t1和t2可以在方法1和方法2中同时运行(反之亦然)
只有在尝试访问方法1时,如果已经获取了锁,则t1或t2将阻止
答案 1 :(得分:4)
声明要同步的方法时,例如:
public synchronized void foo() {
// Do something
}
编译器将其视为您编写的内容:
public void foo() {
synchronized (this) {
// Do something
}
}
在您的示例中,您有一个同步方法和一个非同步方法。这意味着只会锁定对method1
的访问权限。锁定检查仅在进入synchronized
块时完成,因此调用method2
不会触发任何锁定。
要回答你的两个问题,那么,在这两种情况下,两个线程都将被允许继续,因为他们没有试图获得对同一个对象的锁定。如果声明method2
要同步(或手动添加synchronized (this)
块),则会强制一个线程等待另一个线程。
请记住:在对象上进行同步不会阻止其他线程调用该对象上的方法。它只会阻止另一个线程进入具有相同锁定对象的同步块。
顺便说一句,拥有一个内部锁定对象通常更好,而不是声明要同步的方法,例如。
class Foo {
private final Object LOCK = new Object();
public void doSomething() {
synchronized (LOCK) {
// Whatever
}
}
}
否则我可以通过这样做来打破你的线程安全:
class MessEverythingUp {
public MessEverythingUp(Foo foo) {
synchronized (foo) {
while (true) {
System.out.println("Pwnd ur thread safety");
}
}
}
}
因为我正在锁定foo的实例,所以你的synchronized方法(带有隐式的“synchronized(this)”)将无法获得锁定并将永久阻塞。最重要的是,你无法阻止这种情况,因为我可以同步任何我喜欢的对象。显然这个例子是极端的,但如果你对这类事情不小心,你可能会遇到令人讨厌的,微妙的死锁错误。
答案 2 :(得分:3)
在这两种情况下,第二个帖子都有权执行其方法。
由于这两个方法中只有一个包含synchronized
关键字,因此这两种方法都可以同时执行。限制是在任何给定时间只能执行具有该关键字的一个方法,因为执行该方法需要锁定对象。没有关键字的线程不需要锁定,无论被锁定的对象如何,都将始终允许执行。
我还假设method2
中的1000行代码不包含这样的块:
synchronized (this) { }
如果是,那么结果会有所不同。
synchronized
行时,它将等待t1完成method1
并在继续之前释放其锁定。synchronized
代码块内,synchronized
块,则t2将获取锁定,并且t1将在到达同步代码块后立即等待,直到t2完成该方法并释放锁定。答案 3 :(得分:2)
一种方法是同步的,而另一种方法则不同步。因此,无论是否已获取对象上的锁定(在此情况下是方法所属的实例),非同步方法将无阻碍地执行(因为它不会尝试获取或等待锁定)。这意味着在两种情况下两个线程都会在不等待彼此的情况下运行 - 导致对象的状态可能不一致。
答案 4 :(得分:0)
method1()是同步的,因此称为线程安全方法。当多个线程尝试同时访问此方法时,只有实例对象上的锁才能工作。
method2()不是同步的,因此是一个线程不安全的方法,其他线程也可以调用此方法,即使其他一些线程已经锁定实例,这就是为什么这个方法被称为线程不安全方法。
在这两种情况下,你提到一个线程将通过调用method1()获取实例的锁定,而其他线程将尝试访问不安全的method2(),因此两个线程都将执行。
关于
Tushar Joshi,那格浦尔
答案 5 :(得分:0)
两个线程都将执行,就像锁不存在一样。
线程访问方法2永远不会知道它应该获得锁定,因此即使其他线程持有锁定它也会执行。只有同步方法才会保留锁定,因为同步是可选的,并不总是需要甚至是必需的。
如果两个线程都执行method1,则其中一个将阻塞,直到另一个线程退出该方法并释放锁定。
要确保只执行一个线程而所有其他线程都在等待,您必须使两个方法同步。