【问题标题】:How can I ensure thread safety in the following context?在以下情况下如何确保线程安全?
【发布时间】:2015-12-19 01:02:33
【问题描述】:

我有一个名为 processOutbox 的方法。我希望它是线程安全的。我不希望另一个线程在有一个线程时调用此方法。我已经通过以下方式实现了它。我做对了吗?我的执行过程中是否存在任何漏洞?如果有的话,请告诉我如何解决它。

this.start();
    outboxLock.lock();
    timer = new Timer();
    try{
    timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
               processOutbox();
            }
        }, 0, period);
    } finally{
        outboxLock.unlock();
    }

【问题讨论】:

  • 您只锁定了日程安排。执行仍然不是线程安全的。
  • 那我该怎么做呢?请指教。
  • 我建议在类级别的静态变量上同步它。
  • @NamanGala 所以我已经删除了我的问题中的实现。我刚刚使我的方法同步。我应该接受以下答案作为答案吗?
  • 使用单线程ScheduledExecutorService

标签: java multithreading timer locking reentrantlock


【解决方案1】:

如果你想让你的方法processOutbox,你应该使用关键字synchronized

public class YourClass{
    public synchronized void processOutbox(){
         //do all you want
    }
}

更多信息请访问:https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

如果您的代码中有一个 YourClass 实例,例如 myInstance ,则所有对 processOutbox() 的调用都是线程安全的,因为它们将在实例级别锁定。

例如:

YourClass myInstance = new YourClass();
 Thread thread1 = new Thread(){
    public void run(){
      myInstance.processOutbox();
    }
  }
 Thread thread2 = new Thread(){
    public void run(){
       myInstance.processOutbox();
    }
  }
thread1.start();
thread2.start();

thead2 将一直等待直到 thread1 完成对“processOutbox”的调用

但是例如:

YourClass myInstance = new YourClass();
YourClass myInstance2= new YourClass();
Thread thread1 = new Thread(){
    @Override
    public void run(){
        myInstance.processOutbox();
    }
};
Thread thread2 = new Thread(){
    @Override
    public void run(){
        myInstance2.processOutbox();
    }
}
thread1.start();
thread2.start();

thead2 将等待,因为它们在不同的实例上调用该方法。

有人特别询问了如何使用 ReentrantLock -- 所以我将这个回复添加到这个上,因为这个是正确的。

public class YourClass {
    private Lock outboxLock = new ReentrantLock();
    public void processOutbox() {
        outboxLock.lock()
        try {
            // do stuff
        } finally {
            outboxLock.unlock()
        }
    }
}

我特别提到这一点是因为您也可以做一些事情,即通过使用 tryLock 来使其他线程不被锁定而不会导致它们阻塞。

public class YourClass {
    private Lock outboxLock = new ReentrantLock();
    public void processOutbox() {
        if( outboxLock.tryLock() ) {  
            try {
                // do stuff
            } finally {
                outboxLock.unlock()
            }
        }
    }
}

【讨论】:

  • 我不想让另一个线程调用这个方法,而一个线程正在使用它。
  • Java API:“当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。 "
  • 如何使用 reentrantlock 来达到同样的效果?请建议悟空:)
  • 如果你仔细阅读,这里提到的是for an object而不是for all object
  • @NamanGala - 假设 processOutbox() 是一个 instance level 方法。请看,在方法级别使用synchronized 与使用synchronized(this) {..} 相同。锁将在当前对象上。如果两个线程使用 2 个不同的对象来访问此方法,这 2 个对象的状态将不同。因此将有 2 个不同的锁。这很好。
【解决方案2】:

使用CountDownLatch 进行同步。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    相关资源
    最近更新 更多