有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使两个线程执行两个不同的循环或方法?

我有一个算法来计算网格中的一些东西,看起来非常粗略,如下所示:

public class Main {

    pass1 ;
    pass2 ;

    public static void main(String[] args) throws java.lang.Exception {
        Function f = new Function();
        f.solve(pass1, pass2);
    }
}

public class Function {

    public void solve(pass1, pass2) {
        method1(pass1, pass2);
        method2(pass1, pass2);
        method3(pass1, pass2);
    }
    method1(pass1, pass2) {
        //parse grid
        for (row = 0; row < numofrows; row++) {
            for (col = 0; col < numofcols; col++) {
                method4(stuff in here to pass);
                       }
                   }
               }
                  method2(pass1, pass2) {
        //parse grid
        for (row = 0; row < numofrows; row++) {
            for (col = 0; col < numofcols; col++) {
                method4(stuff in here to pass );
                       }
                   }
               }
                  method3(pass1, pass2) {
        //do stuff
    }

    method4(stuff) {
        //add object to hashmap
    }
}

我想使用线程使算法更快

我的想法是让一个线程使用偶数递增计数器执行method1和/或method2,另一个线程使用奇数递增计数器执行,利用更多的cpu,因为现在它只使用25%(我假设是1/4个核)

如果让线程执行method2even()method2odd(),是否可以让线程执行不同的循环或方法?如果是这样的话,我该如何实现这一点,我已经试了好几个小时了,但我无法控制它


共 (1) 个答案

  1. # 1 楼答案

    您的建议是细粒度并行,这可能会因为内存层次结构而导致问题-如果两个线程在同一数组/矩阵的交替索引上操作,那么它们实际上必须直接写入主内存(例如,每次操作后刷新缓存),这可能会导致多线程程序大量运行比单线程程序慢。尽量让线程写入完全不同的内存段,例如,完全不同的阵列/矩阵或同一阵列/矩阵的至少不同部分(例如,thread1写入阵列的前半部分,而thread2写入后半部分-希望它们的阵列段位于不同的缓存线上,并且它们不需要写入主内存以保持一致性);如果线程在相同的内存段上运行,那么请尝试让它们在不同的时间运行,以便它们可以在将最终结果刷新到主内存之前在缓存中计算中间结果

    那么在你的例子中,method1method2method3是相互独立的吗?如果是这样,那么为每个方法使用不同的线程。如果它们不是独立的,例如method1必须在method2之前,必须在method3之前,那么可以使用管道方法:Thread1对矩阵的前N个元素执行method1,然后Thread2对矩阵的前N个元素执行method2,而Thread1对矩阵的第二N个元素执行method1,然后,Thread3对矩阵的前N个元素执行method3,而Thread2对矩阵的第二N个元素执行method2,而Thread1对矩阵的前N个元素执行method1,依此类推,直到所有矩阵元素都已处理完毕

    如果您的线程需要彼此对话(例如,传递矩阵段以进行流水线),那么我更喜欢使用类似于BlockingQueue:Method1和Method2将共享一个队列,Method1向队列中写入元素(通过^{),Method2从队列中读取元素(通过^{)。Method2使用take进行阻塞,直到Method1向其发送一个要处理的矩阵段,然后当Method2使用完矩阵段后,它将通过另一个BlockingQueue将其发送到Method3,然后再次调用与Method1共享的队列上的take


    假设您的方法是独立的,在单独的线程上运行它们的一些代码如下:;可以对其进行修改以适应管道。我省略了MethodN构造函数,您需要在其中传递矩阵等。我使用的是Runnable接口,但正如程序员在评论中所说的,您可以使用CallableExecutorService负责将可运行项分配给线程

    public class Method1 implements Runnable {
        public void run() {
           // execute method1
        }
    }
    
    public class Method2 implements Runnable {
        public void run() {
           // execute method2
        }
    }
    
    public class Method3 implements Runnable {
        public void run() {
           // execute method3
        }
    }
    
    public class Function {
        private ExecutorService executor = Executors.newFixedThreadPool(3);
    
        public void solve(pass1, pass2) {
            Method1 method1 = new Method1(pass1, pass2);
            Method2 method2 = new Method2(pass1, pass2);
            Method3 method3 = new Method3(pass1, pass2);
            executor.submit(method1);
            executor.submit(method2);
            executor.submit(method3);
        }
    }