什么是线程?
线程是进程中的一个实体,线程本身不会独立存在的。
进程是代码再数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一个进程中至少有一个线程,进程中的多个线程共享进程的资源。
线程创建与运行
Java 中有三种线程创建方式:
- 实现 Runnable 接口的 run 方法
- 继承 Thread 类并重写 run 方法
- 使用 FutureTask 方式
继承 Thread 类并重写 run 方法
public class ThreadTest01 extends Thread{
@Override
public void run() {
System.out.println("我是一个子线程。");
}
public static void main(String[] args) {
//创建线程
ThreadTest01 threadTest01 = new ThreadTest01();
//启动线程
threadTest01.start();
}
}
调用 start 方法后线程并没有马上执行而是处于就绪状态,就绪状态是指该线程已经获取除了CPU资源外的其他资源,等待获取CPU资源后才会真正处于运行状态。一旦 run 方法执行完毕,该线程就处于终止状态。
使用继承方式的好处:在 run() 方法内获取当前线程直接使用 this 就可以了,无需使用 Thread.currentThread() 方法;
缺点:Java不支持多继承,如果继承了Thread类,那么就不能再继承其他类。另外任务与代码没有分离,当多个线程执行一样的任务是就需要多份任务代码,而Runnable则没有这个限制。
实现Runnable接口的run方法方式
public class RunnableTask implements Runnable {
public void run() {
System.out.println("我是一个子线程。");
}
public static void main(String[] args) {
RunnableTask runnableTask = new RunnableTask();
new Thread(runnableTask).start();
new Thread(runnableTask).start();
}
}
上面两种方式都有一个缺点:任务没有返回值
使用 FutureTask 方式
public class CallableTask implements Callable<String> {
public String call() throws Exception {
return "hello";
}
public static void main(String[] args) {
//创建异步任务
FutureTask<String> futureTask = new FutureTask<String>(new CallableTask());
//启动线程
new Thread(futureTask).start();
try {
//等待任务执行完毕,并返回结果
String result = futureTask.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
总结:
使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过set方法设置参数或者通过构造函数进行传递,如果使用 runnable 方法,则只能使用主线程里被声明为 final 的变量。不好的地方是 Java 不支持多继承,如果继承了Thread类,那么子类不能再继承其他类,而 runnable 则没有这个限制。前两种方式都没有办法拿到任务的返回结果,但是 FutureTask 方式可以。