2016-12-21 81 views
1

我正在尝试编写一个具有多个线程的Java程序。我有两个在启动时创建的变量。一个是AtomicBoolean,它告诉整个程序何时关闭(即关闭客户端)。另一个变量是一个ConcurrentHashMap,它包含一组在启动时加载的命令。有一些线程包含客户端可运行的客户端已被接受(每个客户端一个线程)运行。还有一个线程通过监听外部变化更新命令到HashMap中(从目录的新命令等)与并发共享变量

这里是代码:

class Program { 
    /* ... other vars like ServerSocket, etc. */ 
    private final ConcurrentHashMap<String, String> mCommands; 
    private final AtomicBoolean mIsListening; 

    public static void main(String[] args) { 
     Program prog = new Program(); 
     prog.loadCommands(); 
     prog.listen(); 
    } 

    public Program() { 
     mCommands = new ConcurrentHashMap<>(); 
     mIsListening = new AtomicBoolean(true); 
     /* other initializations */ 
    } 

    public void loadCommands() { 
     /* Loads commands generated from a directory; updates mCommands, then... */ 
     new Thread(new CommandListenerRunnable(mCommands)).start(); 
    } 

    public void listen() { 
     /* accepting a new client from server socket */ 
     while (mIsListening.get()) { 
      Socket client = ss.accept(); 
      new Thread(new ClientRunnable(client, mCommands, mIsListening)).start(); 
     } 
    } 
} 

正如你所看到的,每我正在创建的孩子,我将这些变量作为参数传递。总而言之,这是分配这些变量的正确方法吗?任何想法将不胜感激。提前致谢!

+1

保持对字段的控制并仅传递对this的引用可能更安全。 – shmosel

+0

@shmosel谨慎地在答案中详细说明,如果它足够,我会将其标记为正确的?尝试了解如何在Runnables的上下文中使用对此的引用。 – Zack

回答

3

我认为设计很好,因为每个线程都应该有它需要的变量的副本。

你说:

例如,我可以使用map.putIfAbsent()使被原子进行

操作,但这并不能使你的地图线程安全的,因为有人可能会调用还有其他的东西。

+0

谢谢您的设计输入。至于第二部分,我明白你在说什么,如果我们正在讨论一个常规的HashMap。但是,我认为ConcurrentHashMap背后的重点是通过允许对它进行原子读取和写入来使线程安全。 – Zack

+1

您可以在这里看到:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html ConcurrentHashMap实现了Map接口,因此它可以获得像put等所有的地图功能。 ...查看API以了解哪些方法和原因不是原子的。 – ddarellis

2

嗯,这不是万无一失的。阅读的ConcurrentHashMap的文档中的所有caveats这样as--

“的汇总状态的方法,包括大小,的isEmpty和 中的containsValue通常是有用的,只有当一个地图没有发生在其他线程 并发更新的结果“。

如果这些限制是可以接受的,那么你有什么好。否则,您将需要您自己的锁定方案来管理访问。

它可能是一样简单的synchronized(sharedLockingObject),或者像ReentrantReadWriteLock一样复杂。

+1

有很多警告。但是,我不认为这是我遇到问题的同步部分。例如,我可以使用map.putIfAbsent()使操作以原子方式执行。我只是更关心我的设计选择是否以正确的方式传递这些变量。 – Zack

+0

@解决方法1:听起来好像您可能正在通过传递自己的布尔值来重新创建线程中断机制来达到相同的目的?但是,我没有看到任何设计缺陷。 –

+0

这是真的。但是,它要么使用全局变量来关闭它们,要么必须存储每个客户端的引用以调用每个子进程的中断。但是非常感谢你的所有意见。 – Zack