Java 如何确保通过匿名可运行对象传递给已运行线程的对象的可见性

Java 如何确保通过匿名可运行对象传递给已运行线程的对象的可见性,java,thread-safety,visibility,runnable,anonymous,Java,Thread Safety,Visibility,Runnable,Anonymous,我一直在阅读Java中的并发性,我了解当通过相同的路径访问对象时,如何使用同步来确保互斥访问和保证可见性,例如,两个线程都访问存储在相同数据结构中的对象 但是,我很难弄清楚如何通过匿名runnable从辅助线程确保对象的可见性,因为该对象不再被同一上下文中的两个线程访问 假设我有一个executor类,如下所示,其中来自其他线程(例如线程1)的对象可以调用execute(),同时发送一个新任务,由executor线程(线程2)执行 我假设线程2在执行Person对象时,不能保证对其所做的更改是可

我一直在阅读Java中的并发性,我了解当通过相同的路径访问对象时,如何使用同步来确保互斥访问和保证可见性,例如,两个线程都访问存储在相同数据结构中的对象

但是,我很难弄清楚如何通过匿名runnable从辅助线程确保对象的可见性,因为该对象不再被同一上下文中的两个线程访问

假设我有一个executor类,如下所示,其中来自其他线程(例如线程1)的对象可以调用execute(),同时发送一个新任务,由executor线程(线程2)执行

我假设线程2在执行Person对象时,不能保证对其所做的更改是可见的,因为线程2很久以前就开始运行了,所以创建线程时不会出现“先发生后发生”的行为

首先,我的假设正确吗?其次,如何确保线程1中对象的任何更改对线程2可见?那么它的子元素——铲子的变化呢

  • 是的,你是对的
  • 使用
    volatile
    Atomic

  • 所以我应该首先将Person'p'分配给Runnable中的volatile Person pInRunnable=p,然后使用它?这会刷新对象的状态(即成员变量)还是仅仅刷新其在内存中的地址?不,您应该使成员变量也具有易变性。阅读volatile关键字:我认为我在这里可能很愚蠢,但是如果我没有访问类实现的权限呢?是否没有办法将其包装起来以确保安全?然后使变量易失性,并用同步块或方法包装所有突变。
    public class BasicExecutor extends Thread {
    
    private final Object monitor = new Object();
    private final ConcurrentLinkedQueue<Runnable> tasks = new ConcurrentLinkedQueue();
    private boolean running = false;
    
    public void execute(Runnable task) {
        tasks.add(task);
    
        synchronized (monitor) {
            if(!running) {
                monitor.notify();
            }
        }
    }
    
    public void run() {
        try {
            while(!Thread.interrupted()) {
                while(tasks.isEmpty()) {
                    synchronized (monitor) {
                        running = false;
                        monitor.wait();
                        running = true;
                    }
                }
    
                tasks.remove().run();
            }
        } catch (InterruptedException e) {
            System.out.println("Executor was interrupted");
        }
    }
    }
    
    final Person p = new Person("Jim");
    p.setName("Rob");
    p.setItem(new Shovel(ShovelType.SILVER));
    
    executor.execute(new Runnable() {
        public void run() {
            // read some information from p
            // do some stuff with that information
        }
    });