3

我有两个线程使用相同的线程,并且由于之前发生的关系,我已经阅读了byObject obj所做的每一个更改都将是可见的。objThread AThread B

我想要做的是相反的,objThread A不可见的情况下改变,Thread B但我不知道如何做到这一点。

我尝试创建一个ThreadLocalin Thread B,将其设置在run()方法中,并使用ThreadLocal.get()而不是objinThread B但它一直在读取更改。

有谁知道如何实现这一目标?

提前致谢

编辑:(MVCE)

public class MyThreadLocal {

    public static final ThreadLocal<Email> threadLocal = new ThreadLocal<Email>();

    public static void set(Email email) {
        threadLocal.set(email);
    }

    public static void remove() {
        threadLocal.remove();
    }

    public static Email get() {
        return threadLocal.get();
    }
}

主线程

serviceEnvioTaskSpring.setThreadName(getIdInstanciaOrigen());   //serviceEnvioTaskSpring is an instance of a class which implements Runnable    

//set some more class' attributes

serviceEnvioTaskSpring.setEmail(email); //email is the shared object

ExecutorService threadExecutor = Executors.newCachedThreadPool();

threadExecutor.execute(serviceEnvioTaskSpring);

threadExecutor.shutdown(); 

线程 B

public void run() {
    try {

        //a few business logic lines

        MyThreadLocal.set(email);
        this.performTask();

    } catch (Exception e) {
        logger.error( "Error al lanzar thread asincrono: "+ e.getMessage()+" - "+e.getCause() );
        e.printStackTrace();
    }
}

public void performTask() {
    //do stuff in a for loop accessing email with MyThreadLocal.get();      
}

当我继续运行主线程时会出现问题,因为它的下一步是刷新整个页面,因此email设置为一个新实例,这使我丢失了 MyThreadLocal 的电子邮件信息

4

1 回答 1

4

我有两个线程使用相同的对象 obj,并且由于之前发生的关系,我已经阅读了线程 A 在 obj 中所做的每个更改对于线程 B 都是可见的。

这是不正确的。或者至少......它是不正确的,因为你已经写了它1

现实情况是,happens-before关系保证更新是可见的。如果没有发生之前的关系,那么这些更改可能是可见的……或者它们可能是不可见的。

我想做的是相反的,在线程 B 中不可见的情况下更改线程 A 中的 obj 但我不知道如何做到这一点。

基本上,你不能保证。如果两个线程正在查看同一个对象,则无法阻止一个线程查看另一个线程的更改。

使用线程局部变量没有帮助。

如果您希望一个线程看不到另一个线程对对象所做的更改,那么您需要复制或克隆该对象并让两个线程使用不同的副本。


1 - (您所写的内容暗示 A 所做的更改将始终对 B 可见,因为存在先发生关系。但不一定存在先发生关系!我承认您可能不是故意的......但我不知道你不是故意的,这就是我迂腐的原因。)

于 2017-09-07T07:52:15.947 回答