在Java中启动多个线程
在Java中启动多个线程
在我的练习中,我需要展示多线程下的资源访问问题。我需要递增共享的(在线程之间共享的)名为histogramTable[]
的int
类型表的索引,表的大小已知,数据存储在文件中。每个线程都有自己的范围,称为interval
。例如:我有4个线程,每个线程获取以下索引:
线程1:0 - 1_000_000
线程2:1_000_000 - 2_000_000
线程3:2_000_000 - 3_000_000
线程4:3_000_000 - 4_000_000
我遇到的问题是,一旦使用给定数量的线程启动程序,即变量threadsNumber
,似乎只有一个线程在运行。因为字节的总和始终为tabSize / threadsNumber。对于上述示例,它是1_000_000字节。根据线程访问的问题,它应该是3_800_000 - 4_000_000字节。你能告诉我我做错了什么吗?
我给你整个代码,因为我认为它很简短。还有一个被注释掉的名为randomizeBytes()
的函数,用于快速生成字节文件。
Ex.java
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class Ex2 { private static int threadsNumber = 4, tabSize = 4000000; public static int threadsCounter; public static byte[] dataTab = loadBytes(); public static byte[] loadBytes() { byte data[] = new byte[tabSize]; Path path = Paths.get("dane.txt"); try { data = Files.readAllBytes(path); } catch (IOException e) { e.printStackTrace(); } return data; } /*private byte[] randomizeBytes() { Path path = Paths.get("binaryData.txt"); byte bytes[] = new byte[tabSize]; new Random().nextBytes(bytes); try { Files.write(path, bytes); } catch (IOException e) { e.printStackTrace(); } return bytes; }*/ public static void runThreads(){ threadsCounter = threadsNumber; int interval = tabSize / threadsNumber; int endIndex = 0; Thread[] threads = new Thread[threadsNumber]; MyThread w; for(int i = 0 ; i < threadsNumber ; i ++){ endIndex = (i + 1) * interval; if(endIndex >= tabSize) endIndex = tabSize; w = new MyThread(interval * i , endIndex); threads[i] = new Thread(w); threads[i].start(); if(threads[i].isAlive()) System.out.println("Thread number: " + i + " started and alive, indexes: " + interval*i + " - " + endIndex ); } } public synchronized static int decrementThreads(){ return --threadsCounter; } public static void main(String args[]){ runThreads(); } }
MyTherad.java
public class MyThread implements Runnable{ private byte table[] = Ex2.dataTab; int startIndex,endIndex,temp; private int histogramTable[] = new int[256] ; private long timeStart, timeStop; public MyThread(int startIndex, int endIndex){ this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { timeStart = System.currentTimeMillis(); for(int i = startIndex ; i < endIndex ; i ++) { temp = Byte.toUnsignedInt(table[i]); histogramTable[temp]++; } timeStop = System.currentTimeMillis(); System.out.println("Threads working: " + Ex2.threadsCounter); if(Ex2.decrementThreads() == 0) printSummary(); } public void printSummary() { int sum = 0; for(int i : histogramTable) System.out.print(i + " "); System.out.println(); for(int i = 0 ; i < 256 ; i ++) sum += histogramTable[i]; System.out.println("Bytes: " + sum); System.out.println("Task complete in: " + (timeStop - timeStart) + "ms"); } }
Java中启动多个线程的方式有很多种,但有时候我们可能会遇到问题,比如线程执行的顺序不符合我们的期望。那么这个问题是怎么出现的呢?该如何解决呢?
在Java中,我们可以使用Thread类的join()方法来解决这个问题。join()方法的作用是使调用该方法的线程等待被调用线程执行完毕。
下面是一个使用join()方法的示例代码:
Thread t1 = new Thread(new Runnable() { @Override public void run() { // 线程1的任务 } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { // 线程2的任务 } }); t1.start(); t1.join(); // 等待线程1执行完毕 t2.start();
在上面的代码中,我们首先创建了两个线程t1和t2,并分别给它们分配了任务。然后我们先启动线程t1,并调用t1.join()方法,这会使当前线程(通常是主线程)等待线程t1执行完毕。当t1执行完毕后,才会继续执行后面的代码。
通过使用join()方法,我们可以保证线程的执行顺序符合我们的期望。在上面的示例中,线程t2会在线程t1执行完毕后启动,从而实现了我们想要的效果。
如果没有使用join()方法,那么线程t1和线程t2的执行顺序是不确定的,可能会出现t2先执行的情况。
总结一下,通过使用Thread类的join()方法,我们可以解决多线程执行顺序不符合期望的问题。只需要在需要等待的线程上调用join()方法,即可保证该线程执行完毕后再继续执行后面的代码。
希望本文对你理解Java中多线程的概念和join()方法有所帮助。如果你想了解更多关于Java多线程的知识,可以参考这篇Java Multithreading concept and join() method上的回答。