【问题标题】:How to isolate variables between threads in Java?如何在Java中隔离线程之间的变量?
【发布时间】:2014-03-21 13:28:05
【问题描述】:

我认为我在运行多线程 Java 程序时遇到了竞争条件。

这是一种置换算法,我想通过运行具有不同值的多个实例来加速该算法。所以我在 Main 类中启动线程:

Runnable[] mcl = new MCL[n1];


for (int thread_id = 0; thread_id < n1; thread_id ++)
    {

    mcl[thread_id] = new MCL(thread_id);
    new Thread(mcl[thread_id]).start();

    Thread.sleep(100);
    }

它运行那些 MCL 类实例。

再次,我认为线程正在访问 MCL 类变量的相同内存空间,对吗?如果是这样,我该如何解决?

我正在尝试制作所有变量数组,其中一个维度与线程的 Id 相关,以便每个线程写入不同的索引。这是一个好的解决方案吗?:

int[] foo = new foo[thread_id];

【问题讨论】:

  • 不,这不是一个好的解决方案。这也不是一个解决方案。
  • 据我所知,您正在运行的那些线程不共享任何公共对象。如果这是真的,您不必同步任何东西(只要每个线程都在他自己的对象上工作)。你能给我们一些你的MCL-class的代码吗?它有任何静态属性吗?
  • 你必须向我们展示 MCL 类。您上传的部分不包含任何竞态条件
  • 为什么不使用Executor 而不是裸线程?
  • 我猜对了!

标签: java multithreading concurrency race-condition


【解决方案1】:

您不能只是事后才考虑线程安全,它需要成为您数据流设计中不可或缺的一部分。

开始、研究和学习以下主题:

1) 同步块、互斥体和最终变量。一个很好的起点:Tutorial。我也很喜欢 Josh Bloch 的 Effective Java,尽管它已经有几年历史了,但它对于编写正确的 Java 程序很有帮助。

2)Oracle's Concurrency Tutorial

3) 了解Executors。除非在最极端的情况下,否则您不必直接管理线程。看到这个tutorial

如果您在线程之间传递非线程安全对象,您将看到不可预知的结果。不可预测意味着分配可能永远不会出现在不同线程之间,或者对象可能处于无效状态(特别是如果您有多个成员字段的数据相互依赖)。

在没有看到 MCL 类的情况下,我们无法为您提供任何有关危险的具体细节,但鉴于您发布的代码示例,我认为您应该退后一步并进行一些研究。从长远来看,它将为您节省时间以正确的方式学习它,而不是解决不正确的并发方案。

【讨论】:

    【解决方案2】:

    如果您想将线程数据分开存储,请将其作为实例变量存储在 Runnables 中(在启动其线程之前初始化每个 Runnable)。不要在数组中保留对它的引用,这只会招来麻烦。

    您可以使用CompletionService 为包装在 Future 中的每个任务获取计算值,因此您无需等待计算值,直到您真正需要该值。评论者推荐的 CompletionService 和 Executor 之间的区别在于,CompletionService 使用 Executor 来执行任务,但它更容易取回数据,see this answer

    这是一个使用 CompletionService 的示例。我正在使用 Callable 而不是 Runnable,因为我想返回结果:

    public class CompletionServiceExample {
    
        public static void main(String[] args) throws Exception {
            ExecutorService executorService = Executors.newCachedThreadPool();
            ExecutorCompletionService<BigInteger> service = 
                    new ExecutorCompletionService<BigInteger>(executorService);
            MyCallable task1 = new MyCallable(new BigInteger("3"));
            MyCallable task2 = new MyCallable(new BigInteger("5"));
            Future<BigInteger> future1 = service.submit(task1);
            Future<BigInteger> future2 = service.submit(task2);
            System.out.println("submitted tasks");
            System.out.println("result1=" + future1.get() );
            System.out.println("result2=" + future2.get());
            executorService.shutdown();
        }
    }
    
    class MyCallable implements Callable<BigInteger> {
    
        private BigInteger b;
    
        public MyCallable(BigInteger b) {
            this.b = b;
        }
    
        public BigInteger call() throws Exception {
            // do some number-crunching thing
            Thread.sleep(b.multiply(new BigInteger("100")).longValue());
            return b;
        }
    }
    

    或者,您可以使用 take 方法在结果完成时检索它们:

    public class TakeExample {
    
        public static void main(String[] args) throws Exception {
            ExecutorService executorService = Executors.newCachedThreadPool();
            ExecutorCompletionService<BigInteger> service = new     
                    ExecutorCompletionService<BigInteger>(executorService);
            MyCallable task1 = new MyCallable(new BigInteger("10"));
            MyCallable task2 = new MyCallable(new BigInteger("5"));
            MyCallable task3 = new MyCallable(new BigInteger("8"));
            service.submit(task1);
            service.submit(task2);
            service.submit(task3);      
            Future<BigInteger> futureFirst = service.take();
            System.out.println(futureFirst.get());
            Future<BigInteger> futureSecond = service.take();
            System.out.println(futureSecond.get());
            Future<BigInteger> futureThird = service.take();
            System.out.println(futureThird.get());
            executorService.shutdown();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-05-06
      • 2019-05-01
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 2021-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多