Java:为什么同步在这里工作

时间:2014-07-04 14:25:07

标签: java multithreading

在下面的代码中,两个线程tr1和tr2访问相同的StringBuilder st。两者都调用了synchronized方法addRemove,它所做的只是将它附加到公共StringBuilder并在离开方法之前删除附加的东西。 我使这个addRemove()方法同步,这意味着每个线程必须等待另一个完成。这意味着离开方法之前字符串构建器st的内容必须与" - "相同。 (在调用方法之前)。但实际上我们得到了这个

Thread# 0 created
Thread# 1 created
Thread# 0:--1
Thread# 1:--1
Thread# 0:--1
Thread# 1:--1
Thread# 0:--1
Thread# 1:--1
Thread# 0:--1
Thread# 0:--1
Thread# 1:--1
Thread# 0:--1
Thread# 1:--1
Thread# 0:--1
Thread# 1:--1
Thread# 0:--1
Thread# 1:--1
Thread# 1:--1
Thread# 1:--1
Thread# 0:--1
Thread# 1:--1
Thread# 0:--

表示字符串" 1"即使在控制离开addRemove()之后,仍然保留在StringBuilder中!这是为什么?毕竟,我让这个方法同步了!

public class MyThread extends Thread{
public static int threadNum=0;
private int myNum=-1;
private StringBuilder st;
public MyThread(StringBuilder st){
    this.st = st;
    myNum = threadNum;
    System.out.println("Thread# "+myNum+" created");
    threadNum++;
}
    public void run(){
        for (int i = 0; i < 10; i++) {
            addRemove();
        }
    }
/**
 * Append and remove at the same time
 */
    private synchronized void addRemove(){
        st.append(myNum+"");
        try {
            Thread.sleep(Math.round(Math.random()*500));
        } catch (InterruptedException e) {
            System.err.println("Thread# "+myNum+" interupted");
        }
        st.deleteCharAt(st.length()-1);
        System.out.println("Thread# "+myNum+":"+st);
    }

    public static void main(String[] args) {
        StringBuilder st= new StringBuilder("--");
        MyThread tr0= new MyThread(st);
        MyThread tr1= new MyThread(st);
        tr0.start();
        tr1.start();
    }

}

4 个答案:

答案 0 :(得分:2)

您正在以默认方式进行同步,这意味着该方法正在this对象(当前实例的对象)上进行同步,并且由于每个线程都是其自己的唯一对象,因此每个实例都将锁定自身。如果你想同步工作,那么该方法应该由一个对象同步,也许是为此目的创建的静态对象。

public static final Object myLock = new Object;

synchronize(myLock) {
  // ....
}

答案 1 :(得分:1)

该方法在每个Thread实例上同步,并且您有许多实例。因此,它就像它根本没有同步一样。

换句话说:方法同步的事实意味着线程必须获取锁才能执行它。要获取的锁定在同步方法(监视器)的对象上。在这种情况下,监视器是线程实例,因此每个线程实例都没有问题来获取它自己的锁。

在这种情况下,您可以在共享资源(如st)上同步块,而不是同步整个方法。

private void addRemove(){
    synchronized(st){
        st.append(myNum+"");
        try {
            Thread.sleep(Math.round(Math.random()*500));
        } catch (InterruptedException e) {
            System.err.println("Thread# "+myNum+" interupted");
        }
        st.deleteCharAt(st.length()-1);
        System.out.println("Thread# "+myNum+":"+st);
    }
}

答案 2 :(得分:0)

创建了两个对象,并且在具有自己的监视器(内部锁定)的各个对象上发生了同步。

如果要在线程访问时使方法同步,请使用可以在同步中使用的公共对象。

答案 3 :(得分:0)

没有任何指定的锁定对象,synchronized会在this上同步;也就是说,你班级的每个实例。使用synchronized(st)同步构建器监视器上的两个线程。