【问题标题】:Parallel task with synchronized arraylist具有同步数组列表的并行任务
【发布时间】:2013-05-31 07:29:56
【问题描述】:

我的作业是使用并行化创建项目,一切都应该是正确的。 然而,我做了我的项目,但我的教授提到我的代码中有问题“请查看数组列表,有问题,也许是同步?”。

我想请你们社区帮助我并指出可能出现的问题。我认为没有用synchronize 括号覆盖我的数组列表可能是个问题,对吗?

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

    /**
    * My project finds all dividors for specific number
    *It must use threads, so I made them. First I start them (first loop) 
    *then join them (second loop). My project must have that loops.
    *Problem might be with not synchronizing methods array list...
    */

    public class Main {

        private final static int NUMBER = 100;
        private final static List<Integer> dividors = new ArrayList<Integer>();

        public static void main(String[] args) {
            new Main().doStuff();
        }
        private int sqr;
        private int sqrp1;

        private void doStuff() {

            sqr = (int) Math.sqrt(NUMBER);
            sqrp1 = sqr + 1;

            Thread[] t = new Thread[sqrp1];

        //starting tasks
            for (int i = 1; i < sqrp1; i++) {
                final int it = i;

                if (NUMBER % i == 0) {
                    final int e = i;

                    t[i] = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println("sta"+e);
                            if (!checkContains(e)) {
                                addElement(e);
                            }

                            final int dividednumber = NUMBER / e;

                            if (!checkContains(dividednumber)) {
                                addElement(dividednumber);
                            }
                        }
                    });
                    t[i].start();
                }
            }

        //calling join for tasks
            for (int i = 1; i < sqrp1; i++) {
                final int it = i;

                if (NUMBER % i == 0) {
                    try {
                        System.out.println("sto"+i);
                        t[i].join();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }


            System.out.println("xxx");

            Collections.sort(dividors);
            Integer[] arrayDividors = dividors.toArray(new Integer[0]);

            for (int i = 0; i < arrayDividors.length; i++) {
                System.out.println(arrayDividors[i]);
            }
        }

        private synchronized void addElement(int element) {
            dividors.add(element);
        }

        private synchronized boolean checkContains(int element) {
            return dividors.contains(element);
        }
    }

我改这部分是对的吗,现在可以了吗?

t[i] = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("waiting " + e);
        synchronized (this) {
            System.out.println("entering " + e);

            if (!checkContains(e)) {
                addElement(e);
            }

            final int dividednumber = NUMBER / e;

            if (!checkContains(dividednumber)) {
                addElement(dividednumber);
            }
            System.out.println("leaving " + e);
        }
    }
});

【问题讨论】:

  • 顺便说一句,您的条件应该是i &lt;= sqrp1,否则平方数会漏掉一个因素。

标签: java multithreading arraylist parallel-processing synchronized


【解决方案1】:

你需要把它变成一个单一的原子操作。

 if (!checkContains(dividednumber)) {
     addElement(dividednumber);
 }

假设你有两个线程。

 T1:  if (!checkContains(dividednumber)) { // false
 T2:  if (!checkContains(dividednumber)) { // false
 T1:      addElement(dividednumber); // adds number
 T2:      addElement(dividednumber); // adds same number

如果您有一个 addElementWithoutDuplicates,则不会发生这种情况。

【讨论】:

  • 针对这个问题,dividednumber 对于任何两个线程都不应该相同,因为它是从递增的计数器中获得的。所以添加相同的数字似乎不太可能。
  • @Santosh 理论上一个数字可以加两次,但上限阻止了这一点。
  • 好的,但是 checkContains 是同步的,对吧?这是否意味着我应该通过synchronize(this){ ... } 覆盖这段代码?
  • @Fishonthegrass 正确。另一个线程可以在两个同步方法之间运行。仅仅因为两种方法是线程安全的,并不意味着它们可以任意组合使用并且仍然是线程保存的。
  • 我编辑了我的问题,现在可以了吗? @PeterLawrey,我应该覆盖synchronized(this) 我的同步 2 方法吗?
猜你喜欢
  • 2012-12-04
  • 1970-01-01
  • 1970-01-01
  • 2011-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多