静态和非静态同步,为什么输出结果不同?
Static and non-static synchronization, why the output results differ?
为什么输出有差异?我有 2 个案例:
- 在第一种情况下,我使用静态函数
f1
和 f2
:
public static synchronized void f1() {
for (int i = 0; i < 100; i++)
System.out.print("A");
}
public static synchronized void f2() {
for (int i = 0; i < 100; i++)
System.out.print("B");
}
这是我的主要方法体:
Thread t1 = new Thread(
new Runnable(){public void run(){f1();}}
);
Thread t2 = new Thread(
new Runnable(){public void run(){f2();}}
);
t1.start();
t2.start();
输出是:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
- 在第二种情况下
f1
和 f2
不是静态的:
public synchronized void f1() {
for (int i = 0; i < 100; i++)
System.out.print("A");
}
public synchronized void f2() {
for (int i = 0; i < 100; i++)
System.out.print("B");
}
输出是如此混乱:
AAABABABBBBAAAAAAAAAABBAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBAA
static
也在 class 应用了一个锁(JLS-8.4.3.6. synchronized
Methods 说,部分地, 对于 class (static
) 方法,使用与方法的 class 的 Class
对象关联的监视器。对于实例方法,与 this
(调用该方法的对象)关联的监视器是使用 )。在您的情况下,您可以从方法中删除 static
并从 System.out
中删除 synchronize
。像
public void f1() {
synchronized (System.out) {
for (int i = 0; i < 100; i++) {
System.out.print("A");
}
}
}
public void f2() {
synchronized (System.out) {
for (int i = 0; i < 100; i++) {
System.out.print("B");
}
}
}
这将强制线程在写入之前获取 System.out
上的锁。
静态同步函数在 class 上同步,而非静态同步函数在实例上同步。
这意味着当函数是静态的时,它们会相互阻塞,而当它们不是(并使用不同的实例)时,它们不会。
如果您的 class 被称为 MyClass
那么:
public static synchronized foo() {...}
类似于:
public static foo() {
synchronized (MyClass.class) {
// ...
}
}
同时:
public synchronized foo() {...}
类似于:
public foo() {
synchronized (this) {
// ...
}
}
通常,您希望指定要同步的对象(您希望独占哪些资源?)并避免在 class/instance 上使用隐式同步,正是因为这个原因。
为什么输出有差异?我有 2 个案例:
- 在第一种情况下,我使用静态函数
f1
和f2
:
这是我的主要方法体:public static synchronized void f1() { for (int i = 0; i < 100; i++) System.out.print("A"); } public static synchronized void f2() { for (int i = 0; i < 100; i++) System.out.print("B"); }
输出是:Thread t1 = new Thread( new Runnable(){public void run(){f1();}} ); Thread t2 = new Thread( new Runnable(){public void run(){f2();}} ); t1.start(); t2.start();
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
- 在第二种情况下
f1
和f2
不是静态的:
输出是如此混乱:public synchronized void f1() { for (int i = 0; i < 100; i++) System.out.print("A"); } public synchronized void f2() { for (int i = 0; i < 100; i++) System.out.print("B"); }
AAABABABBBBAAAAAAAAAABBAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBAA
static
也在 class 应用了一个锁(JLS-8.4.3.6. synchronized
Methods 说,部分地, 对于 class (static
) 方法,使用与方法的 class 的 Class
对象关联的监视器。对于实例方法,与 this
(调用该方法的对象)关联的监视器是使用 )。在您的情况下,您可以从方法中删除 static
并从 System.out
中删除 synchronize
。像
public void f1() {
synchronized (System.out) {
for (int i = 0; i < 100; i++) {
System.out.print("A");
}
}
}
public void f2() {
synchronized (System.out) {
for (int i = 0; i < 100; i++) {
System.out.print("B");
}
}
}
这将强制线程在写入之前获取 System.out
上的锁。
静态同步函数在 class 上同步,而非静态同步函数在实例上同步。
这意味着当函数是静态的时,它们会相互阻塞,而当它们不是(并使用不同的实例)时,它们不会。
如果您的 class 被称为 MyClass
那么:
public static synchronized foo() {...}
类似于:
public static foo() {
synchronized (MyClass.class) {
// ...
}
}
同时:
public synchronized foo() {...}
类似于:
public foo() {
synchronized (this) {
// ...
}
}
通常,您希望指定要同步的对象(您希望独占哪些资源?)并避免在 class/instance 上使用隐式同步,正是因为这个原因。