简体   繁体   English

如何保证对对象的所有非线程安全引用都将被同步?

[英]How to guarantee that all non-thread-safe references to an object will be synchronized?

Suppose I have a class: 假设我有一堂课:

public final class Server {

private final ArrayList<ServerConnection> connections;
private ServerConnection pending;
private Thread connector;

public Server() {
    connections = new ArrayList<>();

    connector = new Thread(() -> {
        while (true) {
            pending = new ServerConnection();
            pending.waitForConnection();

            //Could be adding while another thread is iterating.
            connections.add(pending);
        }
    }, "Connection Establisher");
    connector.setDaemon(true);
    connector.setPriority(Thread.MIN_PRIORITY);
    connector.start();
}

//Anyone with a refrence to this object can access connections.
public ArrayList<ServerConnection> getConnections() {
    return connections;
}
}

How would I make sure that connections is not in use while I add an object. 添加对象时,如何确保未使用connections I thought about using a synchronized (connections) {...} block in the thread but from my knowledge of synchronized blocks all non-thread-safe references to connections would have to be in a synchronized block. 我曾考虑过在线程中使用synchronized (connections) {...}块,但是根据我对synchronized块的了解,所有对connections非线程安全引用都必须位于同步块中。 Is there some way that I can make sure that all non-thread-safe access to connections are synchronized? 有什么方法可以确保所有对connections非线程安全访问都已同步?

Making the getConnections method synchronized is not enough because once the caller gets a reference to the list, it can do whatever it wants with it, including thread unsafe operations. 使getConnections方法同步是不够的,因为一旦调用者获得对该列表的引用,它就可以用它做任何想要的事情,包括线程不安全的操作。

A few simple steps would make your code more robust: 一些简单的步骤将使您的代码更健壮:

  • only use final variables 只使用最终变量
  • provide a start and stop method. 提供一种启动和停止方法。 At the moment you start the thread in the constructor and leak a reference to this - this could have weird visibility effects. 现在,您在构造函数中启动线程并泄漏对此的引用-这可能会产生奇怪的可见性影响。 And you don't manage the thread stopping, making the thread a daemon instead - it works but is probably not as clean. 而且您不管理线程停止,而是将线程改为守护程序-它可以工作,但可能不那么干净。

A simple rewrite could look like the code below (it can certainly be improved) - check the comments. 一个简单的重写可能看起来像下面的代码(可以肯定会得到改善)-检查注释。 Note that it would work better if the waitForConnection reacted to interruption appropriately too, for example by throwing an InterruptedException . 请注意,如果waitForConnection对中断做出适当的反应(例如,抛出InterruptedException ,则效果会更好。

public final class Server {

  //us a thread safe list
  private final List<ServerConnection> connections = new CopyOnWriteArrayList<>();
  //make the thread final
  private final Thread connector;

  public Server() {
    connector = new Thread(() -> {
      //provide a mechanism to stop the thread: exit on interruption
      while (!Thread.currentThread().isInterrupted()) { 
        ServerConnection pending = new ServerConnection();
        pending.waitForConnection();

        //Could be adding while another thread is iterating.
        connections.add(pending);
      }
    }, "Connection Established");
    //Note that the priority may be ignored at runtime
    connector.setPriority(Thread.MIN_PRIORITY);
  }

  public void start() {
    connector.start();
  }

  //to stop the thread, interrupt it
  public void stop() {
    if (!connector.isAlive()) throw new IllegalStateException("The server is not started");
    connector.interrupt();
  }

  //don't return the list but an unmodifiable view of the list
  public List<ServerConnection> getConnections() {
    return Collections.unmodifiableList(connections);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为每个线程创建一个非线程安全对象并使用before-before保证 - Creating one non-thread-safe object per thread and using happens-before guarantee 是否需要同步构造函数中非线程安全集合的变异? - Does mutation of an non-thread-safe collection in a constructor need to be synchronized? Java8中需要非线程安全助手对象的并行方式的惯用方式是什么? - What's the idiomatic way in Java8 to do something parallel that requires a non-thread-safe helper object? 非线程安全字段不应为静态,声纳皮棉错误 - Non-thread-safe fields should not be static, sonar lint error 从非线程安全的方法初始化静态Java常量 - Initializing a static Java constant from a non-thread-safe method 非线程安全尝试实施“如果不存在”? - Non-thread-safe Attempt to Implement Put-if-absent? 如果存在强引用,则保证返回现有对象的线程安全对象池? - Thread Safe Object Pool with Guarantee of Returning Existing Object if Strong References Exist? Java 是否还保证同步之前的所有变量更改对于在同一对象上同步的下一个线程都是可见的? - Does Java also guarantee that all variable changes before synchronized will be visible to the next thread which synchronizes on same object? 使用fork / join可以跨线程边界安全地移植非线程安全值吗? - Can a non-thread-safe value be safely ported across thread boundaries using fork/join? Java8 - 处理Stream的惯用方法 <Callable<…> &gt;并行交付给非线程安全的消费者? - Java8 - idiomatic way to process a Stream<Callable<…>> in parallel delivering to a non-thread-safe consumer?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM