为什么这个线程允​​许另一个线程访问其同步方法?

时间:2011-10-13 16:46:51

标签: java

我有以下代码。我希望一个线程完全执行其synchronized方法,然后允许另一个线程访问相同的方法。但事实并非如此。

public class Threads  {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //Thread Th = new Threads();
        Thread th = new Thread (new thread1 ());
        th.start();
        Thread th1 = new Thread (new thread1 ());
        th1.start();
    }
}



class thread1 implements Runnable{
    String name = "vimal";

    public void run() {
        System.out.println("Runnable "+this.name);
        setNAme("Manish");

    }

    public synchronized void setNAme(String name){
        try {
            System.out.println("Thread "+Thread.currentThread().getName());
            wait(1000);
            this.name = name;
            System.out.println("Name "+this.name);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }   
}

我有一个输出

Runnable vimal
Thread Thread-0
Runnable vimal
Thread Thread-1
Name Manish
Name Manish

在这里使用synchronized有什么用?如何让我的方法在另一个访问之前完全运行?

7 个答案:

答案 0 :(得分:6)

synchronized此处有效果,因为在这两种情况下您都没有在同一个对象上进行同步。应用于实例方法时,synchronized关键字会导致该方法在this上同步。因此,在每种情况下,您都在thread1的实例上进行同步,其中有两个。

当您同时在两个线程中运行thread1相同实例时,将会有更有趣的测试。在这种情况下,调用wait(1000)是一件非常糟糕的事情,因为(如文档所述)它会释放this上的锁。您希望在代码中使用Thread.sleep(1000)

如果您需要有两个thread1实例,则需要在某些共享对象上进行同步,可能是这样的:

private static final Object lockObject = new Object();

public void setName(String newName) {
    synchronized(lockObject) {
        doSetName(newName);
    }
}

答案 1 :(得分:1)

您必须删除对等待(1000)的调用。看起来你真正想要的是调用 Thread.sleep(1000),如果你只想暂停当前线程,这不会释放任何监视器的所有权。

来自Object.wait()的javadoc。

  

此方法使当前线程(称为T)置于其中   等待该对象的设置,然后放弃任何和所有   同步声明此对象。线程T被禁用   线程调度的目的和休眠直到四件事之一   发生的情况:

     
      
  • 其他一些线程调用此对象的notify方法,并且线程T恰好被任意选为线程   唤醒。
  •   
  • 其他一些线程调用此对象的notifyAll方法。
  •   
  • 其他一些线程中断了线程T。
  •   
  • 指定的实时时间已经或多或少。但是,如果超时为零,则不会采用实时时间   考虑和线程只是等待通知。
  •   
     

然后从该对象的等待集中删除线程T.   重新启用线程调度。然后它以通常的方式竞争   与其他线程有权在对象上同步;一旦它   已获得对象的所有控制权   该对象恢复到原状 - 即,到   调用wait方法时的情况。线程T.   然后从wait方法的调用返回。因此,返回时   从wait方法,对象的同步状态和   线程T与调用wait方法时完全一样。

更新:正如其他答案中所提到的,您没有在同一个对象上进行同步。一旦你这样做,由于我提到的问题,你仍然会遭受相同的输出。您需要同时修复所需的结果。

答案 2 :(得分:0)

输出正确,您正在创建不共享任何数据的独立线程。因此,两个线程都以第一个字符串开头,经过一段时间后,字符串会被更改并打印出来。

答案 3 :(得分:0)

您正在创建2个thread1个对象。他们每个人都有自己的setNAme方法。同步方法仅在对象上同步,而不是在类上同步。除非方法是静态的。

答案 4 :(得分:0)

这里有两个具有独立名称变量和独立监视器的线程,因此每个线程只访问自己的成员。如果你想让线程互相交互,你就必须实现这样的交互。

答案 5 :(得分:0)

您正在创建两个单独的thread1对象并运行它们。每个线程都有自己的name变量副本以及setName函数。使它们都是静态的,你会看到同步的效果。

答案 6 :(得分:0)

您正在锁定两个不同的对象实例,根本不需要任何同步。只有在处理共享数据时才需要进行同步。我想你打算写下面的测试。

如果你测试这个,你会发现第二个线程将等到第一个线程用synchronized方法完成。然后取出同步字,你会看到两个线程同时执行。

public class SynchronizeTest {

    public static void main(String[] args) {
        Data data = new Data();

        Thread task1 = new Thread(new UpdateTask(data));
        task1.start();
        Thread task2 = new Thread(new UpdateTask(data));
        task2.start();
    }
}
class UpdateTask implements Runnable {
    private Data data;

    public UpdateTask(Data data) {
        this.data = data;
    }

    public void run() {
        try {
            data.updateData();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    class Data {
    public synchronized void updateData() throws InterruptedException {
        for (int i = 0; i < 5; i++) {
            Thread.sleep(5000);
            System.out.println(i);
        }
    }

}