我有两个线程,我希望在小于某个值时增加一个int变量。我的程序执行此操作但两个不同的线程不会单独增加值
如果one
和two
是两个线程,我希望输出像这样
one 1
two 2
one 3
two 4
one 5
two 6
one 7
two 8...
这是我的计划:
class IncTo100Demo implements Runnable {
public volatile int count = 0;
public void run() {
Thread current = Thread.currentThread();
try {
while(count < 21) {
System.out.println(current.getName() + " count = " + count++);
current.sleep(1000);
}
}
catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread one = new Thread(new IncTo100Demo(), "one");
Thread two = new Thread(new IncTo100Demo(), "two");
try {
one.start();
two.start();
System.out.println("one alive? " + one.isAlive());
one.join();
}
catch(Exception e) {
e.printStackTrace();
}
}
}
,其输出为:
one alive? true
two count = 0
one count = 0
two count = 1
one count = 1
two count = 2
one count = 2
two count = 3
one count = 3
two count = 4
one count = 4
two count = 5
one count = 5
two count = 6
one count = 6
two count = 7
one count = 7
two count = 8
one count = 8
two count = 9
如何让这些线程单独更新变量,以便输出看起来像我想要的那样?
答案 0 :(得分:6)
count
是类IncTo100Demo
的实例变量。每个线程都使用自己的该类实例,因此可以使用自己的该变量副本。这就是他们独立更新价值的原因。要使线程共享,您必须让它们使用相同的类实例,或者必须使count
静态。
此外,一旦两个线程访问相同的count
变量,使该变量为volatile
不足以保证您想要的行为。您可能可能看到该行为,但仍有可能一个线程无法看到该变量的其他更新。这是因为评估表达式count++
并应用其副作用不是原子的。因此,两个线程都可以读取count
的相同值(即,在任何一个写入更新值之前)。在这种情况下,两者都将计算相同的更新值,并且两者都将编写它。结果看起来与您提供的错误输出相似,但可能(非常)偶然,不一致。
为了避免这个问题,您需要同步对count
的访问权限(后者也不需要是易失性的)。您不能通过同步run()
方法来实现这一点,但是,这会使方法使用调用run()
的对象的监视器进行同步。如果你的线程使用相同的IncTo100Demo
实例,那么这将阻止任何并发,如果它们没有,那么那将是无效的。
而是使用run()
内的同步块。如果两个线程共享相同的IncTo100Demo
实例(我建议),那么您可以在该实例上进行同步:
synchronized (this) {
// ... read and manipulate 'count'
}
否则,您需要创建在线程之间共享的另一个对象,并在其上进行同步。请注意,每次循环迭代中对count
的所有访问都在同一个同步块内(包括count < 21
测试),但sleep()
在它之外。您希望同步范围尽可能窄。
由于这似乎是一项教育活动,我会留下详细信息供您解决,但我会给您提示:您可能需要重新构建循环。
答案 1 :(得分:-1)
static 关键字添加 count 变量的声明