Java多线程概述
在Java中,Thread类自身不执行任何操作,它只是驱动赋予它的任务——《Java编程思想》
前言
相信很多初学Java多线程的朋友,在学了各种Runnable、Thread、wait()/notifyAll()之后,虽然能看懂已经写过的多线程代码,但是当自己要用的时候却无从下手,不清楚到底是对象还是什么其他的东西该实现Runnable,线程间的协作机制也不知道怎么加。本文将顺着《Java编程的思想》的思路,尝试概括出入门级别的使用多线程的思想。
多线程概述——多线程本质是什么?
线程有什么用?是一个实体吗?本质是什么?
例子
先从一个小程序出发:以下程序将搜索src
目录下的所有java源代码文件,给定需要匹配的字段,当该java源文件中包含该字段时,输出该文件的路径。
代码的流程图如上所示,可以看到单线程的情况下,遍历文件夹
和判断文件是否包含目标子串
两个任务都由主线程完成。如果单纯是检索文件还好,但如果要求做匹配的同时,又能快速得到整个目录的树形结构呢?显然在java源文件特别多的情况下,主线程就会在检查任务中疲于奔命,只有当所有java文件都检索一边才能得到最后的树形目录,这显然不是我们想要的。
就像“猴子法则”一样,这时候我们就会考虑将判断的检查任务分离出来,交给别人去干,主线程专心做检索目录的工作。
线程的本质
可以看到,上面的例子中,尽量避免直接使用“线程”这个术语,而且我们可以看到,要执行的任务与执行它的实体是不一样的,就好像检查任务我可以交给任何一个人一样。
这样看来,任务本身可以抽象成一个实体,而驱动它的又是另一个实体,而这个驱动任务执行的实体就是线程的本质,在Java中,我们使用 Runnable
接口来表示一个任务实体,用Thread
表示线程实体,使用时一般会将Runnable实体交给线程,让线程去驱动任务进行。
这也是为什么说 Java的Thread类自身不执行任何操作,它只是驱动赋予它的任务
,稍微看过Java多线程的人都会知道另一种实现多线程的方式是继承Thread类,我在初学时也一直误认为“线程就是一个任务”。从概念上讲,我们希望穿件独立于其他任务运行的任务,因此我们应该能够定义任务,从实现的角度看,将任务从线程中分离出来是很有意义的。
线程的使用场景
怎么启动线程(比如说实现Runnable、继承Thread等等的),怎样用线程池等等的,可以查语法书,本文将会概括目前为止我遇到的会用到多线程的情景,然后将其做一个分类。
源代码
先提供本文图例中单线程的代码,多线程的在另一篇文章中会出现。
public class SearchFile {
/**
*
* @param file 查找的目录
* @param pattern 目标字符串
*/
public static void search(File file, String pattern) {
if (file.isFile()) {
if (file.getName().endsWith(".java")) {
String fileContent = readFileContent(file); // 读取文件的内容
if (fileContent.contains(pattern)) {
System.out.format("在 %s 中匹配到了 %s %n", file.getAbsolutePath(), pattern);
}
}
}
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
search(f, pattern);
}
}
}
public static String readFileContent(File file) {
FileReader fileReader = null;
try {
fileReader = new FileReader(file);
char[] chars = new char[(int)file.length()];
fileReader.read(chars);
return new String(chars);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
return null;
} finally {
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
File folder = new File("src");
System.out.println(folder.isDirectory());
search(folder, "static");
}
}