Java 当前对象以外的同步

Java 当前对象以外的同步,java,multithreading,synchronization,Java,Multithreading,Synchronization,我有一个名为counter的类,在该stringbuffer实例中,一个整数变量在两个线程之间共享 我这里的问题是在我使用的计数器类synchronized(buffer)中,buffer只是一个stringbuffer实例 我没有使用synchronized(这个)。根据同步的概念,当我们使用synchronized块时,它将锁定特定实例。如果我们使用了synchronized(this),那么锁就在特定的类实例上,但是我们使用了synchronized(buffer),那么这两个类之间的区别

我有一个名为counter的类,在该stringbuffer实例中,一个整数变量在两个线程之间共享

我这里的问题是在我使用的计数器类synchronized(buffer)中,buffer只是一个stringbuffer实例

我没有使用synchronized(这个)。根据同步的概念,当我们使用synchronized块时,它将锁定特定实例。如果我们使用了synchronized(this),那么锁就在特定的类实例上,但是我们使用了synchronized(buffer),那么这两个类之间的区别是什么呢

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();
  }
}
类计数器实现可运行
{
public StringBuffer=新的StringBuffer();
公共int cnt=0;
@凌驾
公开募捐{
已同步(缓冲区)
{
对于(int i=0;i<100;i++)
{
cnt++;
}
}
}
}
公开课考试{
公共静态void main(字符串[]args){
计数器=新计数器();
线程t1=新线程(计数器);
螺纹t2=新螺纹(计数器);
t1.start();
t2.start();
}
}

实际上这里没有太多的话要说;奇怪,我花了10多分钟才写下我的答案

你看,两个线程中的一个首先获得锁;然后数到100;然后另一个拿了锁;并进一步将计数器增加到200

在你的情况下,如果有,那真的没有什么区别

synchronized(this)

要点是:在这两种情况下,“this”和“buffer”都会导致“相同”的引用。您知道,在您的示例中只有一个计数器对象;所以当这些线程调用run方法时;“这个柜台”;和“counter.buffer”具有相同的效果:两个线程将在一个对象上同步

为了获得不同的结果,您可以将示例修改为:

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);
当你这么做的时候,你会发现sync(buffer)最终还是会给你200;而同步(这个)可以给你各种各样的结果

因为现在,counter1.this和counter2.this不是同一个对象;而counter1.buffer和counter2.buffer是


换句话说:当不同线程“更新”同一对象时;然后,它们在相同的锁上进行同步。因为,如果它们在不同的锁定对象上同步;惊奇-然后没有锁定,没有同步;因此:随机并行写入,已知结果不可预测

人们对固有锁的一个常见误解是,他们认为获取锁可以保护对象的属性。如果你是这么想的,那就不是这样了

每个对象都可以获取其锁,但这对对象的其余部分没有任何影响。在本例中,线程之间共享一个Runnable,该Runnable有一个StringBuffer。因此,只要有一个锁是共享的,那么该锁是在
this
(在可运行状态中)上还是在StringBuffer上,还是在专用锁对象上(表示实例成员
private final object lock=new object()
)都没有区别


用于锁定对象的唯一可能问题(在更大的多线程程序中可能会引起关注)是锁的可用范围。有一个论点认为,使用
this
锁定可能是不好的,因为其他线程也可以获得锁。将锁的范围缩小到私有实例成员(StringBuffer或专用锁对象)可以更容易地推断谁可以获得锁。

当您的
类中有多个共享资源时,差异就会更明显。您可以将示例扩展到两个
计数器
。现在锁定
这将意味着
countA
countB
不能由不同的计数器执行t
线程
同时执行,尽管这些方法是独立的。如果对每个资源都有锁,则只能确保
countA
countB
不能同时执行。仍有可能一个
线程
同时执行
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();
    }
}
类计数器实现可运行{
私有StringBuffer lockA=新StringBuffer();
私有int cntA=0;
私有StringBuffer lockB=新StringBuffer();
私有int cntB=0;
公共财政(a){
已同步(锁定){
对于(int i=0;i<100;i++){
cntA++;
}
System.out.println(“countA:+cntA”);
}
}
公众假期b({
已同步(锁定B){
对于(int i=0;i<100;i++){
cntB++;
}
System.out.println(“countB:+cntB”);
}
}
@凌驾
公开募捐{
countA();
countB();
}
}

仍然令人困惑,您能提供任何与jdbc或集合相关的示例吗
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();
    }
}