我有一个名为counter的类,在stringbuffer实例中,整数变量在两个线程之间共享。
我的问题是在计数器类中我使用了synchronized(缓冲区),缓冲区只不过是一个stringbuffer实例。
我没有使用synchronized(this)。当我们使用synchronized块时,根据同步的概念,它将锁定特定的实例。如果我们使用synchronized(this)然后锁定在特定的类实例上但是我们使用了synchronized(缓冲区),这两者之间有什么区别,任何人都可以深入解释差异。这些类是
class Counter implements Runnable
{
public StringBuffer buffer = new StringBuffer();
public int cnt = 0;
@Override
public void run() {
synchronized (buffer)
{
for (int i = 0; i < 100; i++)
{
cnt++;
}
}
}
}
public class Test {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(counter);
Thread t2 = new Thread(counter);
t1.start();
t2.start();
}
}
答案 0 :(得分:4)
实际上这里没有什么可说的;奇怪的是我花了10多分钟才写下我的答案。
你看,两个线程中的一个首先获得锁定;那么数到100;然后另一个拿锁;并进一步将计数器增加到200.
在你的情况下,如果有
,它确实没有任何区别synchronized(this)
或
synchronized(buffer)
重点是:在这两种情况下,&#34;这个&#34;和&#34;缓冲&#34;导致&#34;相同&#34;参考。你看,你的例子中只有一个 Counter对象;所以当那些线程调用run方法时; &#34; counter.this&#34 ;;和&#34; counter.buffer&#34;具有相同的效果:两个线程将在一个对象上同步。
为了获得不同的结果,您可以将您的示例重新修改为:
public static StringBuffer buffer = new StringBuffer();
public static int ...
然后使用两个计数器对象:
Counter counter1 = new Counter();
Counter counter2 = new Counter();
Thread t1 = new Thread(counter1);
Thread t2 = new Thread(counter2);
当你这样做时,你会发现同步(缓冲)最终仍然给你200;而sync(this)可以为你提供各种结果。
因为现在,counter1.this和counter2.this不是同一个对象;而counter1.buffer和counter2.buffer是!
换句话说:当不同的线程是&#34;更新&#34;同一个对象;然后他们拥有来同步相同锁定。因为,如果他们在不同的锁定对象上同步;惊喜 - 然后没有锁定,没有同步;因此:并行随机写入,具有不可预测性的已知结果!
答案 1 :(得分:0)
人们对内在锁的一个常见误解是他们认为获取锁可以保护对象的属性。如果这就是你的想法,那不是这样的。
每个对象都可以获取其锁,但这对对象的其余部分没有任何影响。在这个例子中,有一个Runnable在线程之间共享,而Runnable有一个StringBuffer。因此,只要存在一个共享的锁,那么该锁是在this
(在Runnable中)还是在StringBuffer上,还是在专用锁对象上(意味着实例成员{{1)没有区别}}
使用哪个对象锁定的唯一可能问题(在更大的多线程程序中可能会引起关注)是锁的可用性范围。有一个论点是,使用private final Object LOCK = new Object()
来锁定可能是错误的,因为锁可用于其他线程,这些线程也可以获取锁定。将锁的范围缩小到私有实例成员(StringBuffer或专用锁对象)可以更容易地推断谁可以获取锁。
答案 2 :(得分:0)
当class
中有多个共享资源时,差异会变得更加清晰。您可以将示例扩展为两个counters
。现在锁定this
意味着countA
和countB
不能同时由不同的threads
执行,尽管这些方法是独立的。如果您锁定了每个资源,则只能确保countA
和countB
无法同时执行。一个thread
仍可能同时执行countA
和另一个countB
。
class Counter implements Runnable {
private StringBuffer lockA = new StringBuffer();
private int cntA = 0;
private StringBuffer lockB = new StringBuffer();
private int cntB = 0;
public void countA() {
synchronized (lockA) {
for (int i = 0; i < 100; i++) {
cntA++;
}
System.out.println("countA:" + cntA);
}
}
public void countB() {
synchronized (lockB) {
for (int i = 0; i < 100; i++) {
cntB++;
}
System.out.println("countB:" + cntB);
}
}
@Override
public void run() {
countA();
countB();
}
}