1.介绍下进程和线程的关系
进程:一个独立的正在执行的程序。
线程:一个进程的最基本的执行单位,执行路径。
多进程:在操作系统中,同时运行多个程序。
多进程的好处:可以充分利用CPU,提高CPU的使用率。
多线程:在同一个进程(应用程序)中同时执行多个线程。
多线程的好处:提高进程的执行使用率,提高了CPU的使用率。
注意:
- 在同一个时间点,一个CPU中只可能有一个线程在执行。
- 多线程不能提高效率,反而会降低效率,但可以提高CPU的使用率。
- 一个进程如果有多条执行路径,则称为多线程程序。
- Java虚拟机的启动至少开启了两条线程:主线程和垃圾回收线程。
- 一个线程可以理解为进程的子任务。
2.说说Java中实现多线程的几种方法
在Java中,实现多线程的常用三种方式是:
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口(JDK 1.5及以上)
- 线程池方式创建
继承Thread类
实现的步骤:
- 创建Thread类的子类。
- 重写run方法。
- 创建线程对象。
- 启动线程。
案例代码:
package com.bobo.thread;
public class ThreadDemo02 {
public static void main(String[] args) {
System.out.println("main方法执行了1...");
// Java中的线程本质上就是一个Thread对象
Thread t1 = new ThreadTest01();
// 启动一个新的线程
t1.start();
for (int i = 0; i < 100; i++) {
System.out.println("main方法的循环..." + i);
}
System.out.println("main方法执行结束了3...");
}
}
class ThreadTest01 extends Thread {
@Override
public void run() {
System.out.println("我们的第一个线程执行了2....");
for (int i = 0; i < 10; i++) {
System.out.println("子线程:" + i);
}
}
}
注意点:
- 启动线程是使用start方法而不是run方法。
- 线程不能启动多次,如果要创建多个线程,则需要创建多个Thread对象。
实现Runnable接口
在这种方式中,可以通过实现Runnable接口来实现线程程序代码和数据的有效分离。
实现的步骤:
- 创建Runnable的实现类。
- 重写run方法。
- 创建Runnable实例对象。
- 创建Thread对象,并把Runnable实现作为Thread构造方法的参数。
- 启动线程。
案例代码:
package com.bobo.runable;
public class RunableDemo01 {
public static void main(String[] args) {
System.out.println("main执行了...");
Runnable r1 = new RunableTest();
Thread t1 = new Thread(r1);
t1.start();
System.out.println("main结束了...");
}
}
class RunableTest implements Runnable {
@Override
public void run() {
System.out.println("子线程执行了...");
}
}
实现Runnable接口的好处:
- 可以避免Java单继承带来的局限性。
- 适合多个相同的程序代码处理同一个资源的情况,较好地体现了面向对象的设计思想。
实现Callable接口
通过实现Callable接口的方式可以获取线程的返回结果,并且可以抛出异常。这种方式在JDK 1.5之后推出。
实现的步骤:
- 创建Callable的实现类。
- 实现call方法,定义返回结果。
- 创建Callable实例对象。
- 使用FutureTask类来封装Callable对象。
- 使用Thread对象来启动线程。
案例代码:
package com.bobo.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class CallableDemo01 {
public static void main(String[] args) throws Exception {
Callable<Integer> callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t1 = new Thread(futureTask);
System.out.println("main方法start....");
t1.start();
System.out.println(futureTask.get());
System.out.println("main方法end ....");
}
}
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum