如何限制创建的线程数并等待主线程直到任何一个线程找到答案?

p2k*_*2kr 8 java parallel-processing performance multithreading java-threads

这是查找 LCM 和 HCF 之和等于该数字的第一对数字(1 除外)的代码。

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

class PerfectPartition {
    static long gcd(long a, long b) {
        if (a == 0)
            return b;
        return gcd(b % a, a);
    }

    // method to return LCM of two numbers
    static long lcm(long a, long b) {
        return (a / gcd(a, b)) * b;
    }

    long[] getPartition(long n) {
        var ref = new Object() {
            long x;
            long y;
            long[] ret = null;
        };

        Thread mainThread = Thread.currentThread();
        ThreadGroup t = new ThreadGroup("InnerLoop");

        for (ref.x = 2; ref.x < (n + 2) / 2; ref.x++) {
            if (t.activeCount() < 256) {

                new Thread(t, () -> {
                    for (ref.y = 2; ref.y < (n + 2) / 2; ref.y++) {
                        long z = lcm(ref.x, ref.y) + gcd(ref.x, ref.y);
                        if (z == n) {
                            ref.ret = new long[]{ref.x, ref.y};

                            t.interrupt();
                            break;
                        }
                    }
                }, "Thread_" + ref.x).start();

                if (ref.ret != null) {
                    return ref.ret;
                }
            } else {
                ref.x--;
            }
        }//return new long[]{1, n - 2};

        return Objects.requireNonNullElseGet(ref.ret, () -> new long[]{1, n - 2});
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        long[] partition = new PerfectPartition().getPartition(n);
        System.out.println(partition[0] + " " + partition[1]);
    }
}
Run Code Online (Sandbox Code Playgroud)

我想在找到第一对后立即停止代码执行。但是,该main线程只是继续运行并打印1n-1
什么是限制数量的最佳解决方案线程数(<256,因为 n 的范围是2max of long)?

预期产出( n=4): 2 2
预期产出( n=8): 4 4

use*_*826 3

首先,您错过了在线程上调用“start”的机会。

new Thread(t, () -> {
    ...
    ...
}, "Thread_" + ref.x).start();
Run Code Online (Sandbox Code Playgroud)

说到你的问题,要限制可以使用线程池的线程数量,例如 Executors.newFixedThreadPool(int nThreads)。

要停止执行,您可以让主线程等待单个计数 CountDownLatch,并在工作线程中成功匹配时对锁存器进行倒计时,并在锁存器等待完成时关闭主线程池。

正如您所问,这里是使用线程池和 CountDownLatch 的示例代码:

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class LcmHcmSum {

    static long gcd(long a, long b) {
        if (a == 0)
            return b;
        return gcd(b % a, a);
    }

    // method to return LCM of two numbers
    static long lcm(long a, long b) {
        return (a / gcd(a, b)) * b;
    }
    
    long[] getPartition(long n) {
        singleThreadJobSubmitter.execute(() -> {
            for (int x = 2; x < (n + 2) / 2; x++) {
                    submitjob(n, x);
                    if(numberPair != null) break;  // match found, exit the loop
            }
            try {
                jobsExecutor.shutdown();  // process the already submitted jobs
                jobsExecutor.awaitTermination(10, TimeUnit.SECONDS);  // wait for the completion of the jobs
                
                if(numberPair == null) {  // no match found, all jobs processed, nothing more to do, count down the latch 
                    latch.countDown();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        try {
            latch.await();
            singleThreadJobSubmitter.shutdownNow();
            jobsExecutor.shutdownNow();
            
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        return Objects.requireNonNullElseGet(numberPair, () -> new long[]{1, n - 2});
    }

    private Future<?> submitjob(long n, long x) {
        return jobsExecutor.submit(() -> {
            for (int y = 2; y < (n + 2) / 2; y++) {
                long z = lcm(x, y) + gcd(x, y);
                if (z == n) {
                    synchronized(LcmHcmSum.class) {  numberPair = new long[]{x, y}; }
                    latch.countDown();
                    break;
                }
            }
        });
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        long[] partition = new LcmHcmSum().getPartition(n);
        System.out.println(partition[0] + " " + partition[1]);
    }
    
    private static CountDownLatch latch = new CountDownLatch(1);
    private static ExecutorService jobsExecutor = Executors.newFixedThreadPool(4);
    private static volatile long[] numberPair = null;
    private static ExecutorService singleThreadJobSubmitter = Executors.newSingleThreadExecutor();      
    

}
Run Code Online (Sandbox Code Playgroud)