我正在测试java中的同步功能,但是看起来我没有正确使用它。我想要两个线程递增一个整数,并且在方法的签名中使用synchronized关键字,递增的结果应该是200000,但是我得到的结果小于200000,这意味着线程没有正确同步。
我的代码:
public class Threadproblem extends Thread {
static long counter;
synchronized public void run() {
for (int i=0; i<100000;i++) {
counter++;
}
}
public static void main(String[] args) {
Threadproblem thr=new Threadproblem();
Threadproblem thr2=new Threadproblem();
thr.start();
thr2.start();
try {
thr.join();
thr2.join();
} catch(InterruptedException e) {
System.out.println(e);
}
System.out.println("Counts:"+counter);
}
}
执行:
Counts:137978
4条答案
按热度按时间ct3nt3jp1#
正确的同步要求对受保护变量的所有访问都在保持 * 相同 * 监视器的同时执行。对于示例方法,
synchronized
关键字会使方法自动获取调用它的示例的监视器。您有两个独立的Threadproblem
示例,因此每个示例都使用自己的监视器。这根本不提供同步。在使用
synchronized
时解决这个问题的一个方法是给予你的类一个synchronized,static 方法来增加计数器,Synchronized static方法使用一个与类关联的监视器,这样你的ThreadProblem
的两个示例就可以使用同一个监视器:或者像@HiranChaudhuri在评论中建议的那样,你可以让两个线程使用同一个
Runnable
对象,同步方法属于这个对象。不管同步问题如何,这样做都更好,因为扩展
Thread
几乎总是错误的。应该通过为线程提供适当的Runnable
来定义线程的工作,而不是重写Thread
本身的run()
方法。请注意,主线程和另外两个线程之间也有可能发生数据竞争,但这些都已经避免了,因为启动一个线程和加入一个线程在所涉及的两个线程之间提供了适当的排序语义。
nnvyjq4y2#
'run'的每次执行都在它自己的对象上同步,这意味着根本没有同步。
您需要在同一对象上进行同步。在您的情况下,类可能是合适的。请将其表示为命名要同步的对象(在本例中为类文本)的“synchronized”语句。
5w9g7ksd3#
Java中的每个Object都有一个隐式锁,这是一个允许同步和互斥的元素。每当你在一个特定的对象上调用一个非静态函数时,它的锁就被获取了,并且在第一个线程释放它之前,其他线程都不能调用该对象上的动态函数。
所以你实际上应该做的是
这里有一个很好的例子:https://www.geeksforgeeks.org/object-level-lock-in-java/
lc8prwob4#
您可以在不需要同步的情况下执行此任务。只需确保增量操作是原子操作。使用
AtomicLong
及其方法而不是counter++
。static AtomicLong counter = new AtomicLong(0);
counter.addAndGet(1);