我们可以执行一个涉及两个线程的操作(嵌套for循环的第二个循环内的逻辑)吗?

时间:2014-01-02 06:39:39

标签: java multithreading

在一次采访中,我被要求打印复合材料编号1到100.我做到了......

int count=0;
for(int i=3;i<=100;i++)
{
    for(int j=2;j<i;j++){
        if(i%j==0)
        count=count+1;
    }
    if(count>0)
        System.out.println(i);
    count=0;
}

然后她让我用两个线程来做。据我所知run()不能接受参数,我们不使用两个线程进行原子操作 是否可以使用两个线程进行此操作?

根据Jigar的建议,我这样写了。

    public class Comp extends Thread{
        int start,last;
        public Comp(int start,int last){
            this.start=start;
            this.last=last;
        }
        public void run(){
            int count=0;
            for(int i=start;i<=last;i++){
                for(int j=i-1;j>=2;j--){
                    if(i%j==0)
                        count=count+1;
                }
                if(count>0)
                    System.out.println(i);
                count=0;
            }
        }

        public static void main(String[] args) {
            Comp c1=new Comp(3,50);
            Comp c2=new Comp(51,100);
            c1.start();
try{c1.join();}catch(Exception e){}
            c2.start();

        }
    }

正确的方法是按顺序获取数字吗?

4 个答案:

答案 0 :(得分:1)

您的代码中的

条件是错误

if(count>0)
           System.out.println(i);

您可能需要一个boolean标志来检测当前号码是否为复合号

您可以将范围分为例如3-50,51-99并将其提供给2个线程

答案 1 :(得分:0)

使用阻止队列可以解决这个问题:

public class CompositCodeTest {
public static void main(String[] args) {
    BlockingQueue< Integer> que = new ArrayBlockingQueue<Integer>(5);
    Thread th1 = new Thread(new PrintThread(que));
    Thread th2 = new Thread(new TestCompositeThread(que));
    th1.start();
    th2.start();
}

}

class PrintThread implements Runnable{

private BlockingQueue< Integer> que ;

public PrintThread(BlockingQueue<Integer> que) {
    super();
    this.que = que;
}

@Override
public void run() {
    boolean start = true;
    while(start){
        int no = 0;
        try {
            no = que.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(no != 1){
            System.out.println(no);
        } else {
            start = false;
        }
    }
}

}

class TestCompositeThread implements Runnable{

私人BlockingQueue&lt;整数&GT; que;

public TestCompositeThread(BlockingQueue<Integer> que) {
    super();
    this.que = que;
}
@Override
public void run() {
    for(int i = 3 ; i < 100 ; i++){
        for(int j = 2 ; j < i ; j++){
            if((i % j) == 0){
                try {
                    System.out.println("ADDED ELEMENT: " + i);
                    que.put(i);
                    break;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    try {
        que.put(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

}

答案 2 :(得分:0)

按线程数分解问题。例如,指定第一个线程打印出前1/2的数字,第二个线程指定另一半。

class CompositeCounter implements Runnable{
 final int start,end;
 public CompositeCounter(int s, int e){
     start = s;
     end = e;
 }
 public void run(){
   int count=0;
   for(int i=start;i<=end;i++)
     {
       for(int j=2;j<i;j++){
          if(i%j==0)
            count=count+1;
    }
    if(count>0)
        System.out.println(i);
    count=0;
  }
}
Thread first = new Thread(new CompositeCounter(3,50);
Thread second = new Thread(new CompositeCounter(51,100);
first.start();
second.start();

答案 3 :(得分:0)

你已经有了工作答案,但假设你使用Java 7,fork / join会很好地运行这个计算。使用fork / join,您可以非常轻松地将工作扩展到您想要的多个线程。

首先,您不必测试将所有数字除以n-1,我完全理解当您处于高温时,这是您没有想到的。去过那里,可以这么说...... 我会用Naive primality test解决问题,如果数字是素数,那么它不是复合词。这需要的值是测试除以2(除非测试数为2)和所有奇数从3到测试数的平方根:

int n = 49;

if (n % 2 == 0 && n != 2) {
    System.out.println("composite");
} else {
    for (int m = 3; m <= Math.sqrt(n); m = m + 2) {
        if (n % m == 0) {
            System.out.println("composite");
            break;
        }
    }

}

此测试将在标准输出上打印复合。现在让我们像第一次测试中那样使用循环来扩展它,但是我们将在列表中添加所有复合(出于某种原因):

private List<Integer> compute(int start, int end) {
    System.out.println("Computation started");
    ArrayList<Integer> compositeList = new ArrayList<>();

    for (int n = start; n <= end; n++) {
        if (n % 2 == 0 && n != 2) {
            compositeList.add(n);
        } else {
            for (int m = 3; m <= Math.sqrt(n); m = m + 2) {
                if (n % m == 0) {
                    compositeList.add(n);
                    break;
                }
            }

        }

    }

    return compositeList;
}

这或多或少是为任务运行fork / join所需要的。我们需要一个ForkJoinPool并告诉池运行任务。为了实现这一点,计算方法必须在fork / join worker实现之一中,并且实现RecursiveTask的类是完美的:

class CompositeFinder extends RecursiveTask<List<Integer>> {

    private int start;
    private int end;

    public CompositeFinder(Integer start, Integer end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected List<Integer> compute() {
        System.out.println("Computation started");
        ArrayList<Integer> compositeList = new ArrayList<>();

        for (int n = start; n <= end; n++) {
            if (n % 2 == 0 && n != 2) {
                compositeList.add(n);
            } else {
                for (int m = 3; m <= Math.sqrt(n); m = m + 2) {
                    if (n % m == 0) {
                        compositeList.add(n);
                        break;
                    }
                }

            }

        }

        return compositeList;
    }

}

这是一个完整的forkable worker类,它将为我们进行部分计算。要静态启动此测试的两个线程,让我们创建一个主类:

public class CompositePoolTest {

    ForkJoinPool forkJoinPool = new ForkJoinPool();

    public static void main(String[] args) {
        new CompositePoolTest().compute();
    }

    public void compute() {

        CompositeFinder firstFinder = new CompositeFinder(1, 50);
        CompositeFinder secondFinder = new CompositeFinder(51, 100);

        forkJoinPool.invoke(firstFinder);
        forkJoinPool.invoke(secondFinder);
        List<Integer> list = firstFinder.join();
        list.addAll(secondFinder.join());
        Collections.sort(list);
        System.out.println(list);

    }

这将输出:

Computation started
Computation started
[4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 64, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100]

compute()方法创建两个forkable并启动它们(invoke)。当他们准备就绪时,他们将再次加入并向我们提供合并和排序的结果。 对于一个小测试来说,这可能看起来像很多代码,但是当你已经掌握了fork / join框架时,它就是一个快乐的编码!总的来说,制作一个可以分割工作的分叉类并分叉它们,让它们在准备好后再加入并继续其余部分。

fork / join框架非常强大,这个测试可以根据需要划分为多个线程,或者由程序自动决定。这是fork / join的经典示例,您可以在Internet上的许多页面上找到它this is one of them。我们所做的是给切片的阈值(THRESHOLD = 10),如果fork中的数字块足够大,它可以被切成两半而另一个fork被制作。通过这样做,任务被切成许多分叉,在动态线程范围内处理给定数量的数字。这是相同测试的完整示例,但会自动切成叉:

public class CompositePoolTest {

    ForkJoinPool forkJoinPool = new ForkJoinPool();

    public static void main(String[] args) {
          new CompositePoolTest().dynamicCompute();
    }

    public void dynamicCompute() {
       DynamicCompositeFinder dynamicFinder = new DynamicCompositeFinder(1,
               100);
       forkJoinPool.invoke(dynamicFinder);
       List<Integer> list = dynamicFinder.join();
       Collections.sort(list);
       System.out.println(list);
    }
}

public class DynamicCompositeFinder extends RecursiveTask<List<Integer>> {

    private static int THRESHOLD = 10;
    private int start;
    private int end;

    public DynamicCompositeFinder(Integer start, Integer end) {
        this.start = start;
        this.end = end;
    }

    protected List<Integer> compute() {
        int midValue = (end - start) / 2;
        if (midValue > THRESHOLD) {
            DynamicCompositeFinder firstHalfFinder = new DynamicCompositeFinder(
                    start, start + midValue);
            firstHalfFinder.fork();
            List<Integer> partialList = new DynamicCompositeFinder(start
                    + midValue + 1, end).compute();
            partialList.addAll(firstHalfFinder.join());
            return partialList;
        } else {
            System.out.println("Computation started for " + start + " to " + end);
            ArrayList<Integer> compositeList = new ArrayList<>();

            for (int n = start; n <= end; n++) {
                if (n % 2 == 0 && n != 2) {
                    compositeList.add(n);
                } else {
                    for (int m = 3; m <= Math.sqrt(n); m = m + 2) {
                        if (n % m == 0) {
                            compositeList.add(n);
                            break;
                        }
                    }

                }

            }

            return compositeList;
        }

    }

}

compute()方法首先检查[数字左侧] / 2是否是一个大于阈值的值,在这种情况下,数字被分成两个分叉,如果需要,然后递归地执行相同的操作。每次拆分都在等待“真实”计算发生,然后在准备好时再次向上合并结果。 运行时,我们将得到以下输出:

Computation started for 64 to 75
Computation started for 14 to 25
Computation started for 39 to 50
Computation started for 51 to 63
Computation started for 89 to 100
Computation started for 76 to 88
Computation started for 26 to 38
Computation started for 1 to 13
[4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 64, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100]