1. 线程介绍
对于计算机来说每一个任务就是一个进程,在进程运行过程中必须至少有一条线程实在运行中。线程本身是不会独立存在的,因为线程是进程中的一个执行路径。
操作系统在分配资源时是把资源分配给进程的,但是CPU资源比较特殊,它是被分配到线程的,因为真正要占用CPU运行的是线程,所以也说线程是 CPU 分配的基本单位。在Java中,当我们启动main函数时其实就启动了一个JVM的进程,而main函数所在的线程就是这个进程中的一个线程,也称主线程。
在单核CPU的计算机中,其实并没有真正的并行运算,一般是使用时间片轮转方式让线程轮询占用的,只不过快速的轮转调度带给你的错觉,让你产生了它们真的在同一时刻同时运行。当然如果是多核CPU,那么并行运行还是真实存在的。
2.JAVA中的线程创建和运行
Java中有三种线程的创建方式,分别为实现Runnable接口的run方法,集成Thread类重写run方法,使用FutureTask方式。
首先来看看Thread类方式的实现
//继承Thread,重写run方法
class MyThread extends Thread{
@Override
public void run() {
System.out.println("run");
}
}
public class ThreadTest {
public static void main(String[] args){
//创建线程
MyThread myThread = new MyThread();
//启动线程
myThread.start();
}
}
从代码中可以看出MyThread类继承了Thread类,并重写了run()方法。在 main 函数中创建了MyThread的实例并调用了start方式启动了线程。
使用继承有个不好的地方就是Java是不支持多继承的,所以如果使用了继承方式,那么就不能再继承其他类。还有就是任务与代码没有分离,当多个线程执行一样的任务时就会产生代码冗余。而Runable就没有这个限制。下面我们来看看Runnable接口的方式。
//实现Runnable接口
class MyThread implements Runnable{
@Override
public void run() {
System.out.println("run");
}
}
public class ThreadTest {
public static void main(String[] args){
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
从上面代码可以看出,两个线程公用了一个代码逻辑,并且MyThread可以继承其他类。但是两种方式都有一个缺点,就是任务没有返回值。下面我们可以来看看FutureTask方式。
//实现Callable接口
class MyThread implements Callable<String>{
@Override
public String call() throws Exception {
return "result";
}
}
public class ThreadTest {
public static void main(String[] args){
//创建任务
MyThread myThread = new MyThread();
FutureTask<String> futureTask = new FutureTask<>(myThread);
//启动线程
new Thread(futureTask).start();
try {
//等待任务执行完成,并返回结果
String result = futureTask.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
上面代码中的MyThread类实现了Callable接口的call()方法。在main函数中创建了一个FutrueTask对象,然后使用FutrueTask对象作为任务创建一个线程并启动。最后通过get()等待任务执行完成拿到结果。
网友评论