将两个不同的方法彼此同步或同步变量
Synchronize two different methods with eachother or synchronize variables
我有一个服务可以被不同的线程访问。该服务有 3 个 long 和两个方法 - 将它们全部相加的方法和将中间一个更改为 0 的方法。
private long a = 10;
private long b = 10;
private long c = 10;
public long add(){
return a + b + c;
}
public void foo(){
b = 0;
}
现在代码当然更复杂了,但关键是当一个线程正在访问 add() 方法时,另一个线程可以访问 foo() 方法并更改 b 的值,所以我永远不确定结果会是什么是。我如何同步这两个方法或同步 a、b、c 变量,以便这将是线程安全的?
您可以将方法声明为同步:
public synchronized long add(){
return a + b + c;
}
public synchronized void foo(){
b = 0;
}
如果您创建方法 synchronized
,那么在任何给定时间都只允许在对象上执行一个方法。如果这个 class 有多个实例,并且它们不是静态的,那么每个实例都可以执行一个方法。在下面的例子中,如果同时调用add
和foo
,其中一个会等待:
public synchronized long add() {
return a + b + c;
}
public synchronized void foo() {
b = 0;
}
注意:同步不构成。也就是说,组合两个 synchronized
事物与组合两个事物然后添加 synchronized
不同。假设您有 synchronized
个方法 getA
、getB
、getC
,那么这个:
public long add2() {
return getA() + getB() + getC();
}
不会 与旧的 add
方法相同,因为某些其他线程可能会在对 getA
的调用之间调用 foo
和 getB
.
一种方法是让另一个 object
说
private object elock = new byte[0];
然后在这两种方法中的每一种中都用
包裹临界区
synchronized(elock) {/* critical section */}
如
public long add(){
synchronized(elock) {
return a + b + c;
}
}
public void foo(){
synchronized(elock) {
b = 0;
}
}
还有更多优化的锁定方案可用,但既然你问的一般,以上就足够了。
你可以像这样使整个线程安全:
private long a = 10;
private long b = 10;
private long c = 10;
public synchronized long add(){
return a + b + c;
}
public synchronized void foo(){
b = 0;
}
将非静态方法标记为 synchronized
具有以下效果:
public synchronized void a() {
// do something
}
// is the same as:
public void a() {
synchronized(this) {
// do something
}
}
并且由于没有两个线程可以同时锁定同一个对象(在本例中对象是 this
),如果一个线程调用 a()
,那么另一个线程调用 b()
, 第二个线程必须等到第一个线程离开 a()
.
您可以了解有关此主题的更多信息here。
请注意,在您的示例中,不足以 仅将一种方法声明为 synchronized
,即使 "only-one-thread-at-a-time" 行为足以实现其中一种方法方法。这是因为 Java Memory Model,一旦您在 Java.
中了解了有关多线程的所有其他内容,就应该立即查看该主题
到目前为止你有四个答案,都告诉你同一件事:同步两种方法。但问题是:即使 与 同步,您仍然永远无法确定结果会是什么。在调用 add() 的线程和调用 foo() 的线程之间存在数据竞争。由 add() 编辑的答案 return 将取决于它是赢得比赛还是输掉比赛。
事实上,在这个特定示例中,同步根本没有增加任何价值。
通过同步,可以保证 foo() 方法调用和 add() 方法调用不会重叠。您可以使用这些知识来证明 add() 将 return 20(如果它输掉比赛)或 30 如果它赢得比赛。
但事实是,在这个特定示例中,由于 JVM 的工作方式,add() 总是 returned 为 20 或 30。
如果计算有更多的步骤,特别是如果它循环并多次引用 b,那么同步就很重要了。有了同步就只有两个可能的答案,但没有同步,其他结果也是可能的。
我有一个服务可以被不同的线程访问。该服务有 3 个 long 和两个方法 - 将它们全部相加的方法和将中间一个更改为 0 的方法。
private long a = 10;
private long b = 10;
private long c = 10;
public long add(){
return a + b + c;
}
public void foo(){
b = 0;
}
现在代码当然更复杂了,但关键是当一个线程正在访问 add() 方法时,另一个线程可以访问 foo() 方法并更改 b 的值,所以我永远不确定结果会是什么是。我如何同步这两个方法或同步 a、b、c 变量,以便这将是线程安全的?
您可以将方法声明为同步:
public synchronized long add(){
return a + b + c;
}
public synchronized void foo(){
b = 0;
}
如果您创建方法 synchronized
,那么在任何给定时间都只允许在对象上执行一个方法。如果这个 class 有多个实例,并且它们不是静态的,那么每个实例都可以执行一个方法。在下面的例子中,如果同时调用add
和foo
,其中一个会等待:
public synchronized long add() {
return a + b + c;
}
public synchronized void foo() {
b = 0;
}
注意:同步不构成。也就是说,组合两个 synchronized
事物与组合两个事物然后添加 synchronized
不同。假设您有 synchronized
个方法 getA
、getB
、getC
,那么这个:
public long add2() {
return getA() + getB() + getC();
}
不会 与旧的 add
方法相同,因为某些其他线程可能会在对 getA
的调用之间调用 foo
和 getB
.
一种方法是让另一个 object
说
private object elock = new byte[0];
然后在这两种方法中的每一种中都用
包裹临界区synchronized(elock) {/* critical section */}
如
public long add(){
synchronized(elock) {
return a + b + c;
}
}
public void foo(){
synchronized(elock) {
b = 0;
}
}
还有更多优化的锁定方案可用,但既然你问的一般,以上就足够了。
你可以像这样使整个线程安全:
private long a = 10;
private long b = 10;
private long c = 10;
public synchronized long add(){
return a + b + c;
}
public synchronized void foo(){
b = 0;
}
将非静态方法标记为 synchronized
具有以下效果:
public synchronized void a() {
// do something
}
// is the same as:
public void a() {
synchronized(this) {
// do something
}
}
并且由于没有两个线程可以同时锁定同一个对象(在本例中对象是 this
),如果一个线程调用 a()
,那么另一个线程调用 b()
, 第二个线程必须等到第一个线程离开 a()
.
您可以了解有关此主题的更多信息here。
请注意,在您的示例中,不足以 仅将一种方法声明为 synchronized
,即使 "only-one-thread-at-a-time" 行为足以实现其中一种方法方法。这是因为 Java Memory Model,一旦您在 Java.
到目前为止你有四个答案,都告诉你同一件事:同步两种方法。但问题是:即使 与 同步,您仍然永远无法确定结果会是什么。在调用 add() 的线程和调用 foo() 的线程之间存在数据竞争。由 add() 编辑的答案 return 将取决于它是赢得比赛还是输掉比赛。
事实上,在这个特定示例中,同步根本没有增加任何价值。
通过同步,可以保证 foo() 方法调用和 add() 方法调用不会重叠。您可以使用这些知识来证明 add() 将 return 20(如果它输掉比赛)或 30 如果它赢得比赛。
但事实是,在这个特定示例中,由于 JVM 的工作方式,add() 总是 returned 为 20 或 30。
如果计算有更多的步骤,特别是如果它循环并多次引用 b,那么同步就很重要了。有了同步就只有两个可能的答案,但没有同步,其他结果也是可能的。