我理解代码块的同步意味着即使很多线程正在等待访问它,特定代码也只会被一个线程访问。
当我们在run方法中编写线程类时,我们通过给出对象来启动synchronized块。 例如
class MyThread extends Thread{
String sa;
public MyThread(String s){
sa=s;
}
public void run(){
synchronized(sa){
if(sa.equals("notdone"){
//do some thing on object
}
}
}
}
这里我们给sa对象提供了同步块的需要。我们将如何为该特定代码块提供同步
答案 0 :(得分:1)
我建议
答案 1 :(得分:1)
synchronized块的参数对象是块锁定的对象。 因此,所有同步块具有相同的对象将彼此排除(以及同一对象的所有同步方法)同时执行。
所以如果你有这个例子
class ExampleA extends Thread() {
public ExampleA(Object l) {
this.x = l;
}
private Object x;
public void run() {
synchronized(x) { // <-- synchronized-block A
// do something
}
}
}
class ExampleB extends Thread() {
public ExampleB(Object l) {
this.x = l;
}
private Object x;
public void run() {
synchronized(x) { // <-- synchronized-block B
// do something else
}
}
}
Object o1 = new Object();
Object o2 = new Object();
Thread eA1 = new ExampleA(o1);
Thread eA2 = new ExampleA(o2);
Thread eB1 = new ExampleB(o1);
Thread eB2 = new ExampleB(o2);
eA1.start(); eA2.start(); eB1.start(); eB2.start();
现在我们有两个同步的块(A和B,在类ExampleA
和ExampleB
中),我们有两个锁定对象(o1和o2)。
如果我们现在看同时执行,我们可以看到:
因此,同步仅取决于参数对象,而不取决于同步块的选择。
在您的示例中,您使用的是:
synchronized(sa){
if(sa.equals("notdone"){
//do some thing on object
}
}
看起来你试图避免有人在你比较它和工作时将你的实例变量sa
更改为另一个字符串 - 但它并没有避免这种情况。
同步不适用于变量,它适用于某个对象 - 所讨论的对象通常应该是包含变量的某个对象(当前的MyThread
对象case,可由this
)或仅用于同步的特殊对象,且不会更改。
正如Peter Lawrey所说,String对象通常是同步锁的错误选择,因为所有相等的String文字都是相同的对象(即将排除彼此的同步块),而相等的非文字字符串(例如在运行时创建)不是同一个对象,因此不会通过其他此类对象或文字排除同步块,这通常会导致细微的错误。
答案 2 :(得分:0)
在此对象上同步的所有线程将等到当前线程完成其工作。例如,如果您对要同步的集合具有读/写操作,则这非常有用。因此,您可以在方法set
和get
中编写同步块。在这种情况下,如果一个线程正在读取信息,则所有其他想要读取或写入的线程都不会等待。
答案 3 :(得分:0)
所以问题是块同步的对象的功能是什么?
Object 的所有实例都具有所谓的监视器。在正常执行中,此监视器是无主的。
希望进入同步块的线程必须拥有对象监视器。但是,一次只能有一个线程拥有监视器。因此,如果监视器当前是无主的,则该线程占有并执行同步的代码块。线程在离开同步块时释放监视器。
如果监视器当前拥有,则需要进入同步块的线程必须等待监视器被释放,以便它可以获得所有权并进入该块。可以等待多个线程,如果有,则只有一个线程将拥有监视器的所有权。其余的将回去等待。