Java多线程开发(一)
一、什么是进程,什么是线程
进程:进程是指在一个系统中正在运行的一个应用程序,程序一旦运行就是进程。
线程:操作系统上的应用程序可以拆分成多个小任务,成对的小任务就是线程,一个进程可以拥有多个线程(每个线程使用的是所属进程的栈空间)。
在某个时刻,CPU的某个核中只能执行一个进程,进程可以拆分成多个线程,CPU会轮换线程执行。
线程是进程的一个实体,是进程的一条执行路径,多个线程共享进程的堆和方法区资源但是每个线程有自己的程序计数器和栈区域。
线程是CPU独立运行和独立调度的基本单位。
二、多线程的好处
多线程是指从软件或者硬件上实现多个线程的并发技术。
线程要么跟CPU进行交互,要么跟硬件进行交互,当线程跟硬件交互时,CPU处于空闲时间。为了提高CPU的利用率(理论上可以是100%),所以引入多线程。
三、创建多线程方式
1、继承Thread类重写run方法(线程执行任务信息),创建对象调用Thread类里start方法来开启线程。
//通过继承Thread类实现自定义线程类
public class MyThread extends Thread {
//线程体
@Override
public void run() {
System.out.println("Hello, I am the defined thread created by extends Thread");
}
public static void main(String[] args){
//实例化自定义线程类实例
Thread thread = new MyThread();
//调用start()实例方法启动线程
thread.start();
}
}
2、实现Runnable接口重写run方法(线程执行任务信息),由Runnable实现类对象来构建Thread类的对象调用start方法开始线程(常用)。
package com.thread;
public class MyRunnable implements Runnable {
//线程体
@Override
public void run() {
System.out.println("Hello, I am the defined thread created by implements Runnable");
}
public static void main(String[] args){
//线程的执行目标对象
MyRunnable myRunnable = new MyRunnable();
//实际的线程对象
Thread thread = new Thread(myRunnable);
//启动线程
thread.start();
}
}
3、实现Callable和Future接口创建线程接口(较为繁琐),具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。
package com.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "Hello, I am the defined thread created by implements Callable";
}
public static void main(String[] args){
//线程执行目标
MyCallable myCallable = new MyCallable();
//包装线程执行目标,因为Thread的构造函数只能接受Runnable接口的实现类,而FutureTask类实现了Runnable接口
FutureTask<String> futureTask = new FutureTask<>(myCallable);
//传入线程执行目标,实例化线程对象
Thread thread = new Thread(futureTask);
//启动线程
thread.start();
String result = null;
try {
//获取线程执行结果
result = futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(result);
}
}
总结:
1、方式1和方式2本质上都是通过实现Runnable接口并重写run()方法,将接口实现类的实例传递给Thread线程类来执行线程体(run()方法中的实现),这里将Runnable接口实现类的实例作为线程执行目标,供线程Thread实例执行;
2、方式3由于Thread类只能执行Runnable接口实现类的执行目标,所以需要对Callable接口的实现类进行包装,包装成Runnable接口的实现类(通过实现了Runnable接口的FutureTask类进行包装),从而使得Thread类能够接收Callable接口实现类的实例,可见这里使用了适配器模式!