1、进程和线程
进程是系统中正在运行的一个程序,是系统资源分配的单位,每个进程都被单独分配有一块独立的内存空间。
线程是是CPU调度和执行的最小单位,每个进程中至少包含有一个线程。
Java程序都是多线程程序,可以通过下下面方法来获取当前的所有活动线程。
public class test {
public static void main(String[] args) {
//获取线程管理
ThreadMXBean mx = ManagementFactory.getThreadMXBean();
//获取所有活动线程
ThreadInfo[] infos = mx.dumpAllThreads(false, false);
//打印输出
for(ThreadInfo info : infos) {
System.out.println(info.getThreadId() + " " + info.getThreadName());
}
}
}
1 main
2 Reference Handler
3 Finalizer
4 Signal Dispatcher
5 Attach Listener
11 Common-Cleaner
12 Monitor Ctrl-Break
上面一段简单的测试代码中,可以看到有 main 线程用来执行我们写的 main 方法。除此之外后台还启动了一些其他的线程用来保证程序的运行。
一个进程通常包含有多个线程,同一个进程中的线程共用该进程的内存空间,而两个进程之间的内存空间是相互独立的。由于一个进程中的线程共用一块内存空间,所以线程间的上下文切换很快,资源开销较少,而进程间的通信需要通过其他方式来实现。
2、多线程
在一个进程中需要同时处理多个任务时,可以建立多个线程来同时计算处理。

在只有一个CPU的计算机中,同一时间点只能处理一条命令,所以会在各线程之间来回切换处理任务,上图红线表示在某一个时间点 CPU 在调度执行对应的线程。所以实际上CPU并不是同时处理多个任务,只是由于在线程之间切换的频率很快,我们在感官上无法感受到这种切换过程,整个处理过程在我们看来就是在同时进行。
3、Java创建线程的 3 种方式
继承 Thread 类
第一步:定义类继承 Thread 类
第二步:重写 run 方法
第三步:创建对象调用 start 方法启动线程(若直接调用 run 方法则相当于正常调用方法,并不会创建线程执行)
class RaceThread extends Thread { //定义类继承 Thread 类
private String name;
private int distance;
public RaceThread(String name) {
this.name = name;
distance = 0;
}
@Override
public void run() { //重写 run 方法
while(distance < 1000) { //模拟 1000 米赛跑
distance++;
System.out.println(name + " 跑了 " + distance + " 米");
}
}
}
public class test {
public static void main(String[] args) {
//创建实例对象
RaceThread t1 = new RaceThread("张三");
RaceThread t2 = new RaceThread("李四");
RaceThread t3 = new RaceThread("王五");
//启动线程
t1.start();
t2.start();
t3.start();
}
}

可以看到在程序运行的过程中,并非某一个任务结束后执行下一个任务,而是三个任务在同时进行。
实现 Runnable 接口
第一步:定义类实现 Runnable 接口
第二步:重写 run 方法
第三步:通过 Thread 对象代理启动线程
class RaceThread implements Runnable { //定义类实现 Runnable 接口
private String name;
private int distance;
public RaceThread(String name) {
this.name = name;
distance = 0;
}
@Override
public void run() { //重写 run 方法
while(distance < 1000) { //模拟 1000 米赛跑
distance++;
System.out.println(name + " 跑了 " + distance + " 米");
}
}
}
public class test {
public static void main(String[] args) {
//创建实例对象
RaceThread t1 = new RaceThread("张三");
RaceThread t2 = new RaceThread("李四");
RaceThread t3 = new RaceThread("王五");
//通过 Thread 对象代理启动线程
new Thread(t1).start();
new Thread(t2).start();
new Thread(t3).start();
}
}
或者可以通过匿名内部类创建 Thread 对象启动线程,不需要定义类去继承 Runnable 接口。通常该线程只需要使用一次时使用,若多次使用会使得代码变得繁琐。
public class test {
static int d = 0;
public static void main(String[] args) {
new Thread(new Runnable() { //通过匿名内部类创建 Thread 对象
@Override
public void run() { //重写 run 方法
while(d < 1000) {
d++;
System.out.println("张三跑了 " + d + " 米");
}
}
}).start(); //启动线程
}
}
实现 Callable 接口
Callable 接口类似于 Runnable 接口,但是 Runnable 接口没有返回值且不能抛出被检查的异常。
第一步:定义类实现 Callable 接口,需要返回值类型
第二步:重写 call 方法,需要抛出异常
第三步:创建实例对象
第四步:创建 FutureTask 对象包装 Callable 接口,线程执行结束后可以获取返回值。
第五步:通过 Thread 对象代理启动线程。
class RaceThread implements Callable<Integer> { //定义类继承 Callable 接口,确定返回值类型
private String name;
private int distance;
public RaceThread(String name) {
this.name = name;
distance = 0;
}
@Override
public Integer call() { //重写 call 方法,有返回值
while(distance < 1000) { //模拟 1000 米赛跑
distance++;
System.out.println(name + " 跑了 " + distance + " 米");
}
return distance; //返回跑完的距离
}
}
public class test {
public static void main(String[] args) {
//创建实例对象
RaceThread t1 = new RaceThread("张三");
RaceThread t2 = new RaceThread("李四");
RaceThread t3 = new RaceThread("老王");
//创建 FutureTask 对象包装
FutureTask<Integer> f1 = new FutureTask<>(t1);
FutureTask<Integer> f2 = new FutureTask<>(t2);
FutureTask<Integer> f3 = new FutureTask<>(t3);
//通过 Thread 对象代理启动
new Thread(f1).start();
new Thread(f2).start();
new Thread(f3).start();
//线程运行结束后可以获取返回值
try {
//通过 get 方法获取返回值
Integer d1 = f1.get();
Integer d2 = f2.get();
Integer d3 = f3.get();
//输出返回值内容
System.out.println("张三共跑完 " + d1 + " 米");
System.out.println("李四共跑完 " + d2 + " 米");
System.out.println("老王共跑完 " + d3 + " 米");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}


运行过程与前面类似,线程运行结束后可以获取到返回值内容。
本文详细介绍了Java中进程与线程的概念,包括它们的区别及如何创建多线程。通过示例代码展示了三种创建线程的方法:继承Thread类、实现Runnable接口和实现Callable接口。
10万+

被折叠的 条评论
为什么被折叠?



