为什么下面的代码不能保证多个线程之间total_home数字的唯一性,即使逻辑处于同步块中。
class Country {
private static int home = 0;
int total_home;
private static synchronized int counter() {
return ++home ;
}
public void getTotal() {
total_home = counter();
}
}
public class T1 extends Thread {
private Country c;
public T1(Country c) {
this.c = c;
}
@Override
public void run() {
for (int i = 0; i <= 10; i++)
c.getTotal();
}
}
public class T2 extends Thread {
private Country c;
public T2(Country c) {
this.c = c;
}
@Override
public void run() {
for (int i = 0; i <= 10; i++)
c.getTotal();
}
}
public class MainClass {
public static void main(String[] args) {
Country c = new Country();
T1 ok = new T1(c);
T2 ok1 = new T2(c);
ok.start();
ok1.start();
}
}
这是一个程序示例。试着运行5-10次,你会发现total_home的值并不是每次都是唯一的。
你的代码有:
Country c = new Country();
T1 ok = new T1(c);
T2 ok1 = new T2(c);
ok.start();
ok1.start();
这应该很明显:计算在代码中执行new Country
的次数。这是...一次。
因此,微不足道的是,只有一个国家对象可用。你的第一个和第二个线程都在引用它。(类似于:它们都有一个唯一的地址簿。但是这些地址簿包含相同的地址。java中的所有对象变量都是引用)。
您的同步代码不是问题,它工作正常-每次调用计数器()
都返回一个唯一的值。
但是,您有两个线程,都在对您创建的同一个国家/地区对象调用getTotal()
。
好的。c
和ok2。c
是相同的(它们指的是同一个对象)。因此,它们的total_home
值当然是相同的——系统中只有一个total_home
,您每次都会覆盖它。
这段代码中有更多内容表明,您需要对java的工作原理做更多的回顾。例如,T1类
和T2类
是完全相同的——那么为什么会有这些呢?
以下是你打算写的,我想:
public static void main(String[] args) throws Exception {
Country c1 = new Country();
Country c2 = new Country();
T1 ok1 = new T1(c1);
T1 ok2 = new T1(c2);
ok1.start();
ok2.start();
System.out.println("These are guaranteed different: " + c1.total_home + " " + t2.total_home);
}
注意:目前有一条投票结果较高的评论建议,您的静态int home
变量“可能”被缓存,您应该向其添加volatile
。这是不正确的-已同步
足以消除所有竞争条件。然而,AtomicInteger
在这里是一个更好的选择——synchronized
是一个相当“昂贵”的度量,AtomicInteger使用明显“更快”的原语(它不使用锁,它使用CPU的比较和设置(CAS)基础设施,速度快了几个数量级)为您提供一个有保证的唯一计数器。
我正试图从同步方法运行异步方法。但是我不能等待异步方法,因为我在同步方法中。我一定不理解TPL,因为这是我第一次使用它。 每个方法都需要前一个方法来完成,因为第一个方法的数据用于第二个方法。 Await运算符只能在异步方法中使用。考虑用'async'修饰符标记此方法,并将其返回类型更改为'task' 但是,如果我使用async修饰符,这将是一个异步操作。因此,如果我对的调用没有使用await运算符
同步调用异步方法最安全的方法是什么?
问题内容: 如果一个同步方法调用另一个同步方法,那么线程安全吗? 问题答案: 是的,将方法标记为时,您实际上是在这样做: 当线程调用从method1进入method2时,它将确保它持有对的锁定,该锁定已经存在,然后可以通过。 当线程直接进入method1或method2时,它将阻塞直到获得锁(),然后进入。 正如詹姆斯·布莱克(James Black)在评论中指出的那样,您必须了解方法主体内部的操
我有点困惑。请看看下面的代码。 我确信调用此序列是可能的。 虽然我仍然有一个小小的困惑,但我们可以很容易地看到也调用方法,这是一个静态方法。方法 是调用非同步静态方法的静态同步方法。当 thread-2 获得类级锁时,为什么从 Thread-1 调用 没有被阻止? 我只是在逻辑上感到困惑,如果一个线程获得类级锁定,则该类其他非同步静态方法保持打开状态,以便从其他方法(实例方法)调用。为什么?