关于Java多线程的一个问题

时间:2010-10-29 11:02:04

标签: java multithreading

假设以下课程

public class TestObject{
    public void synchronized method1(){
        //some 1000 lines of code
    }

    public void method2(){
        //some 1000 lines of code
    }
}

假设有两个线程访问相同的TestObject类实例,让我们称它们为t1和t2。我想知道在下面的场景中会发生什么。

  1. 当t1处于访问method1()的中途时。现在t2正在尝试访问method2()。
  2. 当t1处于访问method2()的中途时。现在t2正在尝试访问method1()。
  3. 我的理解是,对于第一个问题,线程t2将不被授予权限,因为对象将被t1锁定。对于第二个问题,线程t2将被授予访问权并锁定对象并将t1从执行中停止。但我的假设是错误的。有谁能解释一下?

    由于

6 个答案:

答案 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) {
}

如果是,那么结果会有所不同。

  1. t2将被允许开始执行该方法。当它到达synchronized行时,它将等待t1完成method1并在继续之前释放其锁定。
  2. 只要t1不在synchronized代码块内,
  3. t2就会被允许开始执行该方法。如果是,则t2将等待直到t1退出块并在开始之前释放锁定。如果t1尚未进入synchronized块,则t2将获取锁定,并且t1将在到达同步代码块后立即等待,直到t2完成该方法并释放锁定。

答案 3 :(得分:2)

一种方法是同步的,而另一种方法则不同步。因此,无论是否已获取对象上的锁定(在此情况下是方法所属的实例),非同步方法将无阻碍地执行(因为它不会尝试获取或等待锁定)。这意味着在两种情况下两个线程都会在不等待彼此的情况下运行 - 导致对象的状态可能不一致。

答案 4 :(得分:0)

method1()是同步的,因此称为线程安全方法。当多个线程尝试同时访问此方法时,只有实例对象上的锁才能工作。

method2()不是同步的,因此是一个线程不安全的方法,其他线程也可以调用此方法,即使其他一些线程已经锁定实例,这就是为什么这个方法被称为线程不安全方法。

在这两种情况下,你提到一个线程将通过调用method1()获取实例的锁定,而其他线程将尝试访问不安全的method2(),因此两个线程都将执行。

关于
Tushar Joshi,那格浦尔

答案 5 :(得分:0)

两个线程都将执行,就像锁不存在一样。

线程访问方法2永远不会知道它应该获得锁定,因此即使其他线程持有锁定它也会执行。只有同步方法才会保留锁定,因为同步是可选的,并不总是需要甚至是必需的。

如果两个线程都执行method1,则其中一个将阻塞,直到另一个线程退出该方法并释放锁定。

要确保只执行一个线程而所有其他线程都在等待,您必须使两个方法同步。