通过同步作为变量的静态对象我理解的是,如果一个线程正在访问它,其他线程就不能。
class T3
{
static Integer i = 0;
static void callStatic()
{
synchronized(T3.class)
{
System.out.println(i++);
while(true);
}
}
public void notStatic()
{
System.out.println(i++);
while(true);
}
}
class T2 implements Runnable
{
public void run()
{
System.out.println("calling nonstatic");
new T3().notStatic();
}
}
class T implements Runnable
{
public void run()
{
System.out.println("calling static");
T3.callStatic();
}
}
public class Test
{
public static void main(String[] args)
{
new Thread(new T()).start();
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
new Thread(new T2()).start();
}
}
但是这个演示程序输出为:
调用静态
0
调用非静态
1
我的理解错了吗?或者我错过了什么?
我尝试过,同步callStatic
方法,同步T3.class
类对象。但没有一个像我想的那样有效。
注意:我认为,1不会被打印,因为callStatic已锁定变量i并处于无限循环中。
答案 0 :(得分:3)
您不要对变量进行同步,而是在对象上进行同步。
callStatic
在1
上同步,然后将i
设置为2
。如果notStatic
此时要输入synchronized(i)
块,它将在2
上同步。没有其他线程锁定2
,所以它继续。
(实际上,1
和2
不是对象,但Integer.valueOf(1)
和Integer.valueOf(2)
会返回对象,编译器会自动插入Integer.valueOf
调用将int
转换为Integer
s)
在您的代码中,notStatic
根本没有实际同步。确实,在特定时间只有一个线程可以位于特定对象的synchronized
块中,但这对于未尝试输入synchronized
块的其他线程没有影响
答案 1 :(得分:1)
静态和非静态上的同步块不会相互阻塞。您需要了解synchronized
如何为此工作。始终在永远不在变量上的对象上完成同步。同步时,线程会锁定对象的监视器,即放在synchronized
语句中的对象。
静态引用上的同步块(如代码中的)会锁定类的.class对象,而不是该类的任何实例。因此,静态和非静态同步块不会相互阻塞。
现在,在您的代码中,notStatic
方法不会在callStatic
在静态i
Integer对象上同步的任何内容上进行同步。所以他们不会互相阻挡。
答案 2 :(得分:1)
注意:此答案与synchronized(i)
中synchronized(T3.class)
而非callStatic
的原始问题有关。编辑确实改变了问题。
synchronize
作用于对象,而不是持有它的变量/成员。您的代码中有一些重要的事情发生。
synchronize(i)
确实会同步对i
提供的的访问,而其他尝试使用它的代码也会同步。它对不同步的代码没有影响。假设线程A执行synchronize(i)
并保持它(你的无限循环);然后线程B确实System.out.println(i);
线程B可以愉快地读取i
,没有什么能阻止它。线程B必须做
synchronize (i) {
System.out.println(i);
}
...为了受到主题A synchronize(i)
的影响。您的代码是(尝试)同步变异,但不能访问。
i++;
的 Integer
实际上等同于i = new Integer(i.intValue() + 1)
,因为Integer
是不可变的。因此,它会创建一个不同的 Integer
对象,并将其存储在i
成员中。因此,在旧 Integer
对象上进行同步的任何操作都不会影响 new 上的代码同步。因此,即使您的代码同步访问和变异,也没关系,因为同步将在旧对象上。
这意味着callStatic
中的代码正在Integer
的实例上进行同步,然后重复创建一堆其他实例,而这些实例未进行同步。