Java 在方法的ArrayList循环中使用线程
我有一个ArrayList[big one read from a file],我想通过多线程读取它的内容,并处理每个字符串,反复调用一个方法并将其打印到一个文件中。我已经给出了代码的工作结构。。然而,如果我不陷入与线程同步相关的异常中,我就无法编写我想要的代码。。。 我不熟悉线程的概念。。我想找到一种有效的方法来解决这个问题。我已经研究了其他与线程和ArrayList相关的解决方案,但还没有找到适合我的解决方案。。任何关于如何进行的建议都将不胜感激Java 在方法的ArrayList循环中使用线程,java,multithreading,arraylist,Java,Multithreading,Arraylist,我有一个ArrayList[big one read from a file],我想通过多线程读取它的内容,并处理每个字符串,反复调用一个方法并将其打印到一个文件中。我已经给出了代码的工作结构。。然而,如果我不陷入与线程同步相关的异常中,我就无法编写我想要的代码。。。 我不熟悉线程的概念。。我想找到一种有效的方法来解决这个问题。我已经研究了其他与线程和ArrayList相关的解决方案,但还没有找到适合我的解决方案。。任何关于如何进行的建议都将不胜感激 import java.io.Buffer
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
public class threadingWithMathod {
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
ArrayList<String> samples=readurls("path/to/sample.csv");
PrintStream filewriter = new PrintStream(new File("path/to/result.csv"), "UTF-8");
for (int i = 0; i < samples.size(); i++) {
String string1 = samples.get(i);
String string2 = samples.get(i+1);
///Need Info As to how process with Threading without clashing
/// sampleProcessString need to be called repeatedly
//sampleProcessString(filewriter,string) by 2-3 threads
}
}
public static void sampleProcessString(PrintStream filewriter,String string) {
filewriter.println(processedString(string));
}
private static Object processedString(String string) {
//Intended to generate a new line by using a Sql query
//This method will be using a connection to a mysql data base based on sample
return string+"++> done something";
}
public static ArrayList<String> readurls(String filename) {
ArrayList<String> aslink=new ArrayList<String>();
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader( filename));
String line = reader.readLine();
while (line != null) {
aslink.add(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return aslink;
}
}
导入java.io.BufferedReader;
导入java.io.File;
导入java.io.FileNotFoundException;
导入java.io.FileReader;
导入java.io.IOException;
导入java.io.PrintStream;
导入java.io.UnsupportedEncodingException;
导入java.util.ArrayList;
公共类threadingWithMathod{
公共静态void main(字符串[]args)引发FileNotFoundException、UnsupportedEncodingException{
ArrayList samples=readurls(“path/to/sample.csv”);
PrintStream filewriter=新的PrintStream(新文件(“path/to/result.csv”),“UTF-8”);
对于(int i=0;i完成某件事”;
}
公共静态ArrayList readurls(字符串文件名){
ArrayList aslink=新的ArrayList();
缓冲读取器;
试一试{
reader=newbufferedreader(newfilereader(filename));
字符串行=reader.readLine();
while(行!=null){
aslink.add(行);
line=reader.readLine();
}
reader.close();
}捕获(IOE异常){
e、 printStackTrace();
}
返回aslink;
}
}
由于物理磁盘访问,按顺序读取大文件的速度最快。
可以使用内存映射字节缓冲区。
在您的情况下(每行处理)(默认UTF-8)可能就足够了
这是细粒度并发。处理可以通过使用线程池ExecutorService并行完成,因为将有许多线程
你会把结果弄乱的。如果出现问题,请在文件.lines
lambda中传递行号
对于收集结果、在内存中查询结果并将其异步写入文件,可以查看是否有高性能记录器。可能必须这样做
重新实现其功能(取消日志格式)。因此,一个队列线程和一个用于写入文件的线程(一个大字节缓冲区)
可以考虑压缩输出(.CSV.Gz);这将是进一步网络传输的空间/时间增益
实现这一点的方法有很多,因此研究javadoc和变体(例如FutureTask)并查看示例
ThreadPoolExecutor executor = (ThreadPoolExecutor)
Executors.newFixedThreadPool(10);
for (;;) {
Task task = new Task(...);
executor.execute(task);
}
while (!executor.isTerminated()) { ... }
executor.shutdown();
创建了一些代码段,您可以在其中尝试将实际处理代码放入 我的测试数据如下所示:
try (PrintWriter pw = new PrintWriter("testdata.txt")) {
for (int i = 0; i < 1000000; i++)
pw.println(i);
}
其中,line
是输入文件的一行,pw
是输出文件的PrintWriter
。在实际代码中:
try (PrintWriter pw = new PrintWriter("testresult.txt");
BufferedReader br = new BufferedReader(new FileReader("testdata.txt"))) {
String line;
while ((line = br.readLine()) != null)
pw.println(Integer.parseInt(line) * 2);
}
这是一种可以写得更短的内容,并且流式传输可能更具可读性:
try (PrintWriter pw = new PrintWriter("testresult.txt")) {
Files.lines(Paths.get("testdata.txt")).forEach(
line -> pw.println(Integer.parseInt(line) * 2));
}
这两个代码片段产生非常相似的执行时间,在我的机器上大约为1.6-1.7秒(使用“预算”方法测量,long start=System.currentTimeMillis();
before和System.out.println(System.currentTimeMillis()-start);
before和System.out.println(System.currentTimeMillis()-start);
after)
然后,可以使用一个.parallel()
内部的
try (PrintWriter pw = new PrintWriter("testresult.txt")) {
Files.lines(Paths.get("testdata.txt")).parallel().forEach(
line -> pw.println(Integer.parseInt(line) * 2));
}
这将产生混合订单结果。关于
println(int)
的旁注:它没有文档化,但是它的实际实现是,但是如果您想绝对“安全”并且只构建文档化的功能,您应该自己同步它:
try (PrintWriter pw = new PrintWriter("testresult.txt")) {
Files.lines(Paths.get("testdata.txt")).parallel().forEach(line -> {
synchronized (pw) {
pw.println(Integer.parseInt(line) * 2);
}
});
}
它们实际上都比顺序同步慢(2秒和2.2秒,额外的手动同步确实很重要),但是这个处理步骤非常简单当然很重要。因此,重要的是要记住,如果文件操作在您的案例中也占用了时间,那么并行性并不能真正起到帮助作用
为了进行比较,使用线程池的完整代码段:
ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
ExecutorCompletionService<String> ecs = new ExecutorCompletionService<String>(es);
int counter=0;
try (BufferedReader br = new BufferedReader(new FileReader("testdata.txt"))) {
String line;
while ((line = br.readLine()) != null) {
final String current = line;
ecs.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return Integer.toString(Integer.parseInt(current)*2);
}
});
counter++;
}
}
try (PrintWriter pw = new PrintWriter("testresult.txt")) {
while(counter>0) {
pw.println(ecs.take().get());
counter--;
}
}
es.shutdown();
ExecutorService es=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
ExecutorCompletionService ecs=新的ExecutorCompletionService;
int计数器=0;
try(BufferedReader br=newbufferedreader(newfilereader(“testdata.txt”)){
弦线;
而((line=br.readLine())!=null){
最终串电流=线路;
ecs.submit(新的可调用(){
@凌驾
公共字符串调用()引发异常{
返回Integer.toString(Integer.parseInt(当前)*2);
}
});
计数器++;
}
}
try(PrintWriter pw=newprintWriter(“testresult.txt”)){
而(计数器>0){
println(ecs.take().get());
计数器--;
}
}
es.shutdown();
这无疑是其中最长的一个,另一方面,它运行2秒,因此与同步的更少的流样本相当,没有它是“安全的”,因为文件操作都发生在主线程中(w
ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
ExecutorCompletionService<String> ecs = new ExecutorCompletionService<String>(es);
int counter=0;
try (BufferedReader br = new BufferedReader(new FileReader("testdata.txt"))) {
String line;
while ((line = br.readLine()) != null) {
final String current = line;
ecs.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return Integer.toString(Integer.parseInt(current)*2);
}
});
counter++;
}
}
try (PrintWriter pw = new PrintWriter("testresult.txt")) {
while(counter>0) {
pw.println(ecs.take().get());
counter--;
}
}
es.shutdown();