【问题标题】:java multithreading synchronization confirmation?java多线程同步确认?
【发布时间】:2016-10-14 10:17:40
【问题描述】:

1) 如果使用了 synchronized(this),这意味着两个线程中的任何一个都将锁定因子实例并增加 val 变量值直到循环退出。 所以 synchronized(this) 在这里意味着我们不应该使用任何其他实例变量。我们只能在同步块中使用因子实例的变量吗?

2) 如果 synchronized(addition) 在这里意味着我们只能使用 add 变量而不是 factor 实例类的 val 变量?

关于这个同步块有很大的困惑。 我的理解是同步块将锁定对象的实例并保护操作并使其线程安全。但是使用不同的实例实际上意味着它应该只保护特定的实例变量而不是任何其他实例变量。任何人都可以用下面提供的代码深入解释与此相关的概念

class Factor implements Runnable
{
 int val = 0;
Addition addtion = new Addition();

@Override
public void run()
{

    currInsLock();
    diffInsLock();
}

// locking on the current instance which is this
// we will use synchronized(this)

public void currInsLock() 
{
    synchronized (this) 
    {
        for(int i=0;i<100;i++)
        {
                try
                  {
                     Thread.sleep(100);
                  }
                catch (InterruptedException e)
                {
                      e.printStackTrace();
                }   
        System.out.println(Thread.currentThread().getName()+"---val value lock on this obj -->"+val++);

        }
    }
}



// locking on the different instance
public void diffInsLock() 
{
    synchronized (addtion) 
    {

        for(int i=0;i<100;i++)
        {
                try
                  {
                     Thread.sleep(100);
                  }
                catch (InterruptedException e)
                {
                      e.printStackTrace();
                }   
        System.out.println(Thread.currentThread().getName()+"---val value lock on addition obj -->"+val++);
        System.out.println(Thread.currentThread().getName()+"---add value lock on addition obj -->"+addtion.add++);
        }
    }
}

}

加法类:

public class Addition  
{
   public int add=0;
}

主类

 public class ConcurrentDoubt {

 public static void main(String[] args)
{
  Factor factor=new Factor();

  Thread thread1=new Thread(factor);
  Thread thread2=new Thread(factor);

   thread1.start();
   thread2.start();

}
}

【问题讨论】:

    标签: java multithreading synchronization


    【解决方案1】:

    你用作对象的监视器并不重要,它可以是任何对象,我什至会说理想情况下我们不应该使用this 作为对象的监视器,而是使用private final Object 实例来更好地保护我们的类,因为如果在您的代码之外,我们使用您的类的实例作为对象的监视器,它可能会阻止您的类正常工作。

    关键点是在您想要修改或访问您想要保护的任何内容(成员变量、类实例...)时使用完全相同的对象监视器,如果您想要保护的内容在 @ 之外被访问/修改987654323@ 块或使用不同对象的监视器,您的代码不再是线程安全的,因为您不再阻止并发访问或修改。实际上,对于给定对象的监视器,只有一个线程可以执行受 synchronized 块保护的代码,因此如果您有 2 个不同的对象监视器来保护同一事物,则可以有 2 个线程访问/修改您尝试保护的内容。

    所以在这里,您使用thisaddtion 作为对象的监视器来保护您的成员变量val,因此您的代码不是线程安全的,您需要使用同一个对象的监视器。

    假设你想使用this作为对象的监视器来保护你的成员变量val,你的代码应该是:

    synchronized (addtion) {
        for(int i=0;i<100;i++) {
            ...
            synchronized (this) {
                System.out.println(
                    Thread.currentThread().getName() + 
                    "---val value lock on addition obj -->" + val++
                );
            }
            System.out.println(
                Thread.currentThread().getName() + 
                "---add value lock on addition obj -->" + addtion.add++
            );
        }
    }
    

    【讨论】:

    • OP:“......使用不同的实例确实意味着它应该只保护特定的实例变量而不是任何其他实例变量......” - 我想你需要强调线程的互斥,因此块内对数据的所有访问都是按线程排序的。
    • @VictorSorokin thx 的反馈,但坦率地说我还是不太清楚OP的这句话。但是你的提议就是我所说的your code is no more thread safe because you don't prevent concurrent accesses or modifications anymore
    • @VictorSorokin 我稍微修改了我的答案以添加您的评论,谢谢
    • 我看到它就像 OP 没有意识到对 all 实例变量的访问是针对特定同步块内的代码进行排序的,而不仅仅是用作监视器的代码(实际上,对于 所有块内访问的数据,而不仅仅是实例变量)。但我可能错了:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    • 2011-01-16
    相关资源
    最近更新 更多