【问题标题】:Multithreading/Parallelizing each item of for loop JAVA多线程/并行化for循环JAVA的每一项
【发布时间】:2016-12-01 01:10:17
【问题描述】:

我试图让每个线程访问单个项目的 for 循环,而另一个线程访问下一个项目。我想使用多个线程来执行此操作,并且创建的多个线程的数量将由用户输入。我已经使用 executorservice 和流完成了这项工作。我想使用简单的线程来做到这一点。下面是正确的吗?有没有更好的办法?

Map<String, String> fileMap = new HashMap<>();
fileMap.put("Age", "Age is not remotely associated with it.");
fileMap.put("Gender", "Gender plays a role but not that important.");
fileMap.put("Money", "People do not believe but this is the only factor that matters.");

Runnable myRunnable = new Runnable(){
    public void run(){
        for (Map.Entry<String, String> entry : fileMap.entrySet()) {
            synchronized(this){
                int counter = 0;
                Pattern p = Pattern.compile("not");
                Matcher m = p.matcher(entry.getValue());
                while (m.find()) {
                    counter++;
                }
                System.out.println("File Name: " + entry.getKey());
                System.out.println("Count: " + counter);
                System.out.println(Thread.currentThread().getName());
            }
        }
    }    
};

int n = Integer.parseInt(args[0]);
for (int x=0; x<n; x++)
{
    Thread temp= new Thread(myRunnable, "Thread #" + x);
    temp.start();
    System.out.println("Started Thread:" + x);
}

另外,由于前一个线程已经计算了值,是否有可能让一个线程不返回上一个项目? 任何帮助,将不胜感激。谢谢

【问题讨论】:

  • 似乎没有线程,然后由于synchronized而试图阻止它运行。虽然在这种情况下this 是什么?如果您想阻止它重新处理已找到的行,则可以将其从 map 中删除
  • 我不清楚你所说的简单线程是什么意思。 Java 线程没有索引(例如您在 OpenCL/Cuda 中看到的),因此如果您想为线程提供索引,则需要扩展线程的功能,尽管您的可运行对象可以保存索引。您在此应用程序中的逻辑也存在缺陷,因为您创建的线程数并不总是与您正在处理的项目数相匹配。至少我会将您的 for 循环从 x&lt;n 更改为 x &lt; n &amp;&amp; x &lt; fileMap.size()
  • @RalphRitoch 请原谅我的英语。我的意思是“使用简单的线程来做到这一点”,而不是通过 ExecutorService 或任何其他包。只是线程以及 Maps/ConcurrentHashMaps

标签: java multithreading


【解决方案1】:

这是您的问题的解决方案。这会解析线程名称以提供索引,并使用最终数组来处理将数据传递到线程中。

Map<String, String> fileMap = new HashMap<>();
fileMap.put("Age", "Age is not remotely associated with it.");
fileMap.put("Gender", "Gender plays a role but not that important.");
fileMap.put("Money", "People do not believe but this is the only factor that matters.");


final int[] tgSize = new int[]{0};
final Map.Entry[][] entryArr = new Map.Entry[1][];

Runnable myRunnable = new Runnable(){
    public void run(){
        Integer index = Integer.valueOf(Thread.currentThread().getName().substring(8));

        for(int i = index; i < fileMap.size(); i += tgSize[0]) {
            int counter = 0;
            @SuppressWarnings("unchecked")
            Map.Entry<String, String> entry = entryArr[0][i];
            Pattern p = Pattern.compile("not");
            Matcher m = p.matcher(entry.getValue());
            while (m.find()) {
                counter++;
            }
            synchronized(this) {
                System.out.println("File Name: " + entry.getKey());
                System.out.println("Count: " + counter);
                System.out.println(Thread.currentThread().getName());            
            }
        }
    }    
};

int n = Integer.parseInt(args[0]);

tgSize[0] = n < fileMap.size() ? n : fileMap.size();
entryArr[0] = fileMap.entrySet().toArray(new Map.Entry[fileMap.size()]);


for (int x=0; x<n && x < fileMap.size(); x++)
{
    Thread temp= new Thread(myRunnable, "Thread #" + x);
    temp.start();
    System.out.println("Started Thread:" + x);
}

【讨论】:

  • 谢谢。这完美地工作,我正在寻找什么。但是你能告诉我为什么我们需要创建 Map.Entry[ ][ ]?
  • 我明白了。它会进入数组以供稍后处理,对吗?
  • 正确,它是 GPU 处理工作原理的一面镜子。首先将数据设置到全局内存中,然后使用索引处理项目以确保着色器不会做同样的工作。最终数组是在 java 中模拟全局(共享)内存的好方法。
【解决方案2】:

可以通过AbacusUtilparalledStream实现

final Pattern p = Pattern.compile("not");

Stream.of(fileMap).parallel(threadNum).map(entry -> {
    Matcher m = p.matcher(entry.getValue());
    int count = 0;
    while (m.find()) {
        count++;
    }
    return Pair.of(entry.getKey(), count);
}).forEach(entry -> {
    N.println("File Name: " + entry.getKey() + ", Count: " + entry.getValue());
});

如果你想自学如何编写多线程代码。这是一个简单的示例:

final int threadNum = 3;
final ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
final Iterator<Entry<String, String>> iter = fileMap.entrySet().iterator();

for (int i = 0; i < threadNum; i++) {
    executorService.execute(new Runnable() {
        @Override
        public void run() {
            Entry<String, String> entry = null;
            while (true) {
                synchronized (iter) {
                    if (iter.hasNext() == false) {
                        break;
                    }
                    entry = iter.next();
                }

                final Matcher m = p.matcher(entry.getValue());
                int count = 0;
                while (m.find()) {
                    count++;
                }

                System.out.println("File Name: " + entry.getKey() + ", Count: " + count + ", thread: " + Thread.currentThread().getName());
            }
        }
    });
}

声明:我是AbacusUtil的开发者。

【讨论】:

  • 不错的库,但他确实在问题中说他想使用“简单”线程。他也没有定义简单是什么意思。
  • 你的库在 maven 上吗?
  • 嘿,我真的很喜欢你提到的这个库!
  • @Ralph,我根据您的 cmets 编辑答案。是的,它在 Maven 上
  • @GOXR3PLUS,很高兴知道你喜欢它
【解决方案3】:

使用遍历数组的原始线程并行化循环的标准方法如下所示,使用您的问题。

import java.util.*;
import java.util.regex.*;

public class MyClass {

public static void main(String[] args) {
    Map<String, String> fileMap = new HashMap<>();
    fileMap.put("Age", "Age is not remotely associated with it.");
    fileMap.put("Gender", "Gender plays a role but not that important.");
    fileMap.put("Money", "People do not believe but this is the only factor that matters.");
    String[] keys = fileMap.keySet().toArray(new String[fileMap.size()]);

    int n = 2; //Integer.parseInt(args[0]);
    for (int x=0; x<n; x++)
    {
        Runnable myRunnable = new MyRunnable(fileMap, keys, x, n);
        Thread temp= new Thread(myRunnable);
        temp.start();
        //System.out.println("Started Thread:" + x);
    }
}

    private static class MyRunnable implements Runnable {
        private Map<String, String> fileMap;
        private String[] keys;
        private int threadID;
        private int threadCount;
        Pattern p = Pattern.compile("not");
        public MyRunnable(Map<String, String> fileMap, String[] keys, int threadID, int threadCount) {
            this.fileMap = fileMap;
            this.keys = keys;
            this.threadID = threadID;
            this.threadCount = threadCount;
        }
        public void run(){
            for (int i=threadID; i<keys.length; i+= threadCount) {
                int counter = 0;
                Matcher m = p.matcher(fileMap.get(keys[i]));
                while (m.find()) {
                    counter++;
                }
                synchronized(MyClass.class){
                    System.out.println("File Name: " + keys[i]);
                    System.out.println("Count: " + counter);
                    System.out.println("ThreadID: " + threadID);
                }
            }
        }    
    }
    }

【讨论】:

  • 谢谢。我试图在不创建另一个类的情况下做到这一点。但解决方案更简单。谢谢
猜你喜欢
  • 2017-09-25
  • 2019-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-09
  • 2021-06-29
相关资源
最近更新 更多