在下面的代码中,两个线程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();
}
}
答案 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)
同步构建器监视器上的两个线程。