【问题标题】:java threading lock variable properlyjava线程锁变量正确
【发布时间】:2015-11-30 11:55:17
【问题描述】:

线程 A 会:

class A{
    public String value;
    public void methodA(String value){ //lets say value="test"
        this.value=value;
        //some code
        // Thread B interrupts
        System.out.println(value); // prints "haha" but I want it to be "test"
    }
}

线程 B 会:

class B{
    public void methodB(){
        a.setValue("haha");  
    }
}

methodB 和 methodA 是一些监听方法,它们在不同的线程中执行。

只要methodA 还没有完成,我如何确保该值不会改变?但我也希望之后将“哈哈”分配给价值。所以我希望 B 等到 A 完成 methodA 然后将“haha”分配给 value。

【问题讨论】:

  • 我的问题是这不是一个定义的路径。所以方法B可以在方法A完成后执行(我想要的结果)。也可能是 MethodB 在 MethodA 之前执行。但有时,MethodB 会中断 MethodA,我会遇到这个问题
  • 一个非常基本的解决方案是将methodAsetValue 都设为synchronized。然后你会想阅读 Oracle 并发教程,这样你就明白你刚刚做了什么。

标签: java thread-safety synchronized


【解决方案1】:

最简单的方法是在更改字段值的方法上使用“同步”关键字。

例如我们有存储数据的类:

public class Data {
   String value = "";
   public synchronized void setValue(String val) {
      this.value = val;
      System.out.println(val);
   }
}

然后线程只使用这种方法来更新值。一次只有一个线程可以执行此方法(无中断)。

如果你想在两种方法上传播它(就像我想的那样)。您可以使用两个选项。或者在这两种方法上都使用synchronized,或者使用外部锁对象。

如果你想确定,例如线程 A 必须首先执行,你可以使用CountDownLatch 对象,它会停止其他线程,直到线程 A 不会减少锁存器。

有很多方法可以处理同步。您应该更准确地了解您想要实现的目标以及您想要处理的场景类型。例如 - a.setValue("haha") 是 A 类的方法吗?

我还建议查看有关并发 https://docs.oracle.com/javase/tutorial/essential/concurrency/ 的文档。

【讨论】:

  • 假设我有 2 个方法 setValue1(String value) setValue2(String value) 都设置值;
  • 如果他们是一个类的成员,那么关键字synchronized 就足够了。否则,您可以这样做,例如 ReentrantLock 对象,您必须将其提供给两个类。然后使用流程,例如 1. 锁定、2. 更改值、3. 解锁。
【解决方案2】:

如果您只想在调用methodB() 之前完成methodA(),那么您应该从同一个线程调用这两个方法。一般来说,如果你想让你的程序按一定的顺序做某些事情,最好的方法是 在一个线程中完成所有事情。

另一方面,您可能希望两个线程在大多数时间并行工作,但可能有一个特定点您不希望线程 B 通过,直到线程 A 到达那里。 Java 标准库提供了多种不同的同步对象供您使用。例如,java.util.concurrent.CountDownLatch

初始化:

CountDownLatch countDownLatch=new CountDownLatch(1);
threadA.start();
threadB.start();

线程 A:

doSomeStuff();
methodA();
countDownLatch.countDown();
doSomeMoreStuff();

线程B:

doSomeOtherStuff();
countDownLatch.await();
methodB();
doSomeMoreOtherStuff();

doSomeStuff() 和 doSomeOtherStuff() 调用可能同时发生,doSomeMoreStuff() 和 doSomeMoreOtherStuff() 调用可能同时发生,但在这种情况下 methodA() 和 methodB() 将被序列化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    相关资源
    最近更新 更多