-
作用:
为什么要引入线程?其实就是为了提高cpu利用率,也就是效率。
-
基本概念:
什么是进程?什么是线程?简单来说,进程好比一个APP,而线程就是其底下的任务,而任务是可以有多个的,也就是多线程,当然进程也可以多个,但这里不讨论。线程不能独立的存在,它必须是进程的一部分。就像main()方法,main()就是一个主线程 / 进程,其底下分出的线程任务就是子线程。
多线程与单线程就好比说,我们来比100公里谁跑的快,单线程就是一个人从头跑到尾,而多线程则是多个人合作跑,那效率肯定是多线程高啦,但是多线程要处理好协作的问题,不然你说那几个吊毛万一在争论这段路谁来跑,谁也不让睡,那效率肯定大打折扣,甚至可能低于单线程。
-
线程的生命周期
新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态:
如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
创建线程
-
Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口;
- 通过继承 Thread 类本身;
- 通过 Callable 和 Future 创建线程。
-
通过 Callable 和 Future 创建线程(有返回值)
-
创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
-
创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
-
使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
-
调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
-
-
实例
有10个文件,每个文件里有10000000个随机生成的数,每个数的大小都在1~1000之间,写一个程序,依次读取每个文件,统计每个文件里每个数字出现的次数,再汇总。
public class Parallel {
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void main(String[] args) throws ExecutionException,
InterruptedException, IOException {
System.out.println("----Program starting----");
Date date1 = new Date();
int taskSize = 4;//线程的数目无法确定
//create a Thread pool with taskSize tasks
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
ArrayList<Future<Map<String, Integer>>> list = new ArrayList<>(10);
String filepath = System.getProperty("user.dir");
filepath += "/src/data/";
File file = new File(filepath);
File[] filelist = file.listFiles();
for (int i = 0; i < filelist.length; i++) {
Callable c = new MyCallable(filelist[i]);
// get Future with return value
FutureTask f = (FutureTask) pool.submit(c);
list.add(f);
}
// block Thread until done
pool.shutdown();
try {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
//count map
Map<String, Integer> map = new HashMap<>(1000);
for (int i = 1; i <= list.get(0).get().size(); i++) {//统计i从1到1000,也就是1~1000的次数
int sum=0;
for (int j = 0; j <list.size(); j++)//从10个Future获取某个数字出现的次数
sum += list.get(j).get().get(i+"");
if (!map.containsKey(i+""))
map.put(i+"", sum);
else
map.put(i+"", map.get(""+i)+sum);
}
//write to r.txt
write_r(map);
Date date2 = new Date();
System.out.println("Program running time:"+ (date2.getTime()
- date1.getTime()) + "ms");
//about 7200ms
}
//write to r.txt
public static void write_r(Map<String, Integer> map) throws IOException {
File writename = new File("src/r.txt");
writename.createNewFile();
BufferedWriter out = new BufferedWriter(new FileWriter(writename));
for (int j = 1; j <= map.size(); j++) {
out.write(j+","+map.get(j+"")+"\n");
}
out.flush(); // flush file
out.close(); // close file
}
}
class MyCallable implements Callable {
private File file;
private Map<String, Integer> map = new HashMap<>();
public MyCallable(File file) {
this.file = file;
}
// deal files
@SuppressWarnings("resource")
public static void deal_Files(File file, Map<String, Integer> map) throws IOException {
InputStreamReader reader = new InputStreamReader(new
FileInputStream(file));
BufferedReader br = new BufferedReader(reader);
String line = "";
while ((line = br.readLine()) != null) {
if (!map.containsKey(line))
map.put(line, 1);
else
map.put(line, map.get(line) + 1);
}
}
@Override
public Object call() throws Exception {
deal_Files(file, map);
return map;
}
}
- 10个文件生成脚本
//获得路径
String filepath = System.getProperty("user.dir");
System.out.println(filepath);
filepath += "/src/data/";
for (int k = 1; k < 11; k++) {
File file = new File(filepath + k + ".txt");
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
Random random = new Random();
for (int i = 0; i < 10000000; i++) {
//生成1~1000的随机数
int nums = Math.round(random.nextInt(1000)+1);
//将int 转化为 String类型
bw.write(Integer.toString(nums));
bw.newLine();
}
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
-
再补充下 Java对文件的处理,#具体代码#