Java多线程初学者问题

时间:2009-10-07 16:48:58

标签: java multithreading scientific-computing

我正在研究一种科学的应用程序,该应用程序具有可以并行执行的易于分离的部分。所以,我已经将这些部分作为独立线程写入每个运行,但不是因为看起来是将事物分成线程的标准原因(即,不阻止某些退出命令等)。

几个问题:

这实际上是否会在标准的多核桌面上给我带来任何东西 - 也就是说,如果我有一个当前的JVM,那么线程实际上是在单独的内核上运行,还是我必须做其他事情?

我有很少的对象被所有线程读取(尽管从未写过)。那个潜在的问题?这些问题的解决方案?

对于实际的集群,你能推荐框架将线程分发到各个节点,这样我就不必自己管理(好吧,如果存在的话)?澄清:通过这个,我的意思是要么自动将线程转换为单个节点的任务,要么使整个集群看起来像一个JVM(即,它可以将线程发送到它可以访问的任何处理器)或其他什么。基本上,在集群上以有用的方式实现并行化,因为我已经将它构建到算法中,而我的工作量最小。

奖励:大多数评估包括集合比较(例如,union,intersection,contains)以及来自键的一些映射以获得相关集合。我在FORTRAN,C和C ++(第一个科学计算学期和10年前的另外两个HS AP课程的学期)方面经验有限 - 如果我绑了我的话,我会发现什么样的速度/易于并行化收益? Java前端到其中一种语言的算法后端,以及我的经验水平可能会在那些语言中实现这些操作会带来什么样的麻烦?

3 个答案:

答案 0 :(得分:8)

  • 是的,使用独立线程将在普通JVM中使用多个核心,而无需您做任何工作。

  • 如果只读过任何内容,多个线程读取它应该没问题。如果你可以使有问题的对象成为不可变的(保证它们永远不会被改变),那就更好了

  • 我不确定您正在考虑哪种群集,但您可能需要查看Hadoop。请注意,分布式计算分发任务而不是线程(通常,无论如何)。

答案 1 :(得分:5)

多核用法

Java运行时通常会调度线程以在所有可用的处理器和内核上并发运行。我认为可以限制这一点,但需要额外的工作;默认情况下,没有限制。

不可变对象

对于只读对象,将其成员字段声明为final,这将确保在创建对象时永远不会更改它们。如果字段不是final,即使它在构造之后从未改变,在多线程程序中也可能存在一些“可见性”问题。这可能导致一个线程所做的分配永远不会对另一个线程可见。

多个线程访问的任何可变字段都应声明为volatile,受同步保护,或使用其他并发机制来确保更改在线程之间保持一致且可见。

分布式计算

在Java中使用最广泛的分布式处理框架称为Hadoop.它使用了一个名为map-reduce.的范例

本机代码集成

与其他语言集成不太可能值得。由于其自适应字节码到本机编译器,Java在各种计算任务上已经非常快。如果没有实际测试,假设另一种语言更快是错误的。此外,使用JNI与“本机”代码集成非常繁琐,容易出错且复杂;使用像JNA这样的简单接口非常慢,很快就会消除任何性能提升。

答案 2 :(得分:1)

正如有些人所说,答案是:

  1. 核心上的线程 - 是的。 Java长期以来一直支持本机线程。大多数操作系统都提供了内核线程,可自动调度到您拥有的任何CPU(实现性能可能因操作系统而异)。

  2. 简单的答案是一般来说是安全的。更复杂的答案是你必须确保实际创建了你的对象。在任何线程可以访问它之前初始化。这可以通过以下两种方式解决:

    • 让类加载器使用Singleton(和延迟类加载)解决问题:

      public class MyImmutableObject
      {
          private static class MyImmutableObjectInstance {
              private static final MyImmutableObject instance = new MyImmutableObject();
          }
          public MyImmutableObject getInstance() {
              return MyImmutableObjectInstance.instance;
          }
      }
      
    • 明确使用获取/释放语义来确保一致的内存模型:

      MyImmutableObject foo = null;
      volatile bool objectReady = false;
      
      // initializer thread:
      ....
      /// create & initialize object for use by multiple threads
      foo = new MyImmutableObject();
      foo.initialize();
      
      // release barrier
      objectReady = true;
      
      // start worker threads
      public void run() {
         // acquire barrier
         if (!objectReady)
             throw new IllegalStateException("Memory model violation");
      
         // start using immutable object foo
      }
      

    我不记得如何利用Java的内存模型来执行后一种情况。我相信,如果我没记错的话,对volatile变量的写入等同于释放障碍,而从volatile变量读取等同于获取障碍。此外,与对象相反,使布尔波动的原因是由于存储器模型约束,易失性变量的访问更加昂贵 - 因此,布尔值允许您强制执行存储器模型&然后可以在线程内更快地完成对象访问。

  3. 如上所述,有各种各样的RPC机制。还有RMI,它是在远程目标上运行代码的本机方法。还有像Hadoop这样的框架,它们提供了更完整的解决方案,可能更合适。

  4. 为了调用本机代码,它非常难看 - Sun真的不鼓励使用JNI是一个丑陋复杂的混乱,但它是可能的。我知道至少有一个用于加载的商业Java框架。执行本机动态库而无需担心JNI(不确定是否有任何免费或OSS项目)。

  5. 祝你好运。