文章目录个人语录:时间不负有心人,星光不问赶路人,以顶级好的态度写一篇博客
上次面试的时候面试官出了一道,多线程的题,自己八股文背多了,实操起来拉胯的一匹,纸上得来终觉浅,明知此事需躬行
- Java多线程多种实现方式
- 1、继承Thread类实现多线程
- 常规使用
- 简便使用:匿名类
- 区别
- 案例
- 2、Runnable接口方式实现多线程
- 常规使用
- 简便使用:匿名类
- 案例
- 3、Callable和FutureTask获取异步任务
- Futrue接口
- Callable接口
- FutureTask类
- 案例
- 线程池实现
// 步骤1:创建线程类 (继承自Thread类)
class MyThread extends Thread{
// 步骤2:复写run(),内容 = 定义线程行为
@Override
public void run(){
... // 定义的线程行为
}
}
// 步骤3:创建线程对象,即 实例化线程类
MyThread mt=new MyThread(“线程名称”);
// 步骤4:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止
// 此处采用 start()开启线程
mt.start();
简便使用:匿名类
// 步骤1:采用匿名类,直接 创建 线程类的实例
new Thread("线程名称") {
// 步骤2:复写run(),内容 = 定义线程行为
@Override
public void run() {
// 步骤3:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止
}.start();
区别
案例
public class ThreadDemo {
public static void main(String[] args) {
MyThread thread = new MyThread("线程一");
thread.start();
MyThread2 thread2 = new MyThread2("线程二");
thread2.start();
}
}
class MyThread extends Thread{
String name ;
public MyThread(String name){
this.name = name;
}
public void run(){
System.out.println(name+"正在运行");
}
}
class MyThread2 extends Thread{
String name ;
public MyThread2(String name){
this.name = name;
}
public void run(){
System.out.println(name+"正在运行");
}
}
2、Runnable接口方式实现多线程
常规使用
// 步骤1:创建线程辅助类,实现Runnable接口
class MyThread implements Runnable{
....
@Override
// 步骤2:复写run(),定义线程行为
public void run(){
}
}
// 步骤3:创建线程辅助对象,即 实例化 线程辅助类
MyThread mt=new MyThread();
// 步骤4:创建线程对象,即 实例化线程类;线程类 = Thread类;
// 创建时通过Thread类的构造函数传入线程辅助类对象
// 原因:Runnable接口并没有任何对线程的支持,我们必须创建线程类(Thread类)的实例,从Thread类的一个实例内部运行
Thread td=new Thread(mt);
// 步骤5:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止
// 当调用start()方法时,线程对象会自动回调线程辅助类对象的run(),从而实现线程操作
td.start();
特别注意:
- Java中真正能创建新线程的只有Thread类对象
- 通过实现Runnable的方式,最终还是通过Thread类对象来创建线程
简便使用:匿名类所以对于 实现了Runnable接口的类,称为 线程辅助类;Thread类才是真正的线程类
// 步骤1:通过匿名类 直接 创建线程辅助对象,即 实例化 线程辅助类
Runnable mt = new Runnable() {
// 步骤2:复写run(),定义线程行为
@Override
public void run() {
}
};
// 步骤3:创建线程对象,即 实例化线程类;线程类 = Thread类;
Thread mt1 = new Thread(mt, "窗口1");
// 步骤4:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止
mt1.start();.
案例
-
应用场景:创建两个线程-实现一个耗时任务
-
实例说明:实现2个窗口同时卖火车票;两个窗口一共卖100张,卖票速度均为1s/张
public class RunableDemo {
public static void main(String[] args) {
Runnable1 runnable1 = new Runnable1();
Thread thread = new Thread(runnable1, "窗口一");
Thread thread2 = new Thread(runnable1, "窗口二");
thread.start();
thread2.start();
}
}
class Runnable1 implements Runnable {
private volatile int ticket = 100;
@Override
public void run() {
while (ticket > 0) {
synchronized (this){
ticket--;
System.out.println(Thread.currentThread().getName() + "卖掉1张票,剩余" + ticket + "张票");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3、Callable和FutureTask获取异步任务
场景: 我们要计算1+…+10和20+…+30相加的结果,当然可以用a=1+…+10,b=20+…+30,之后resutl=a+b。 但实际上第一个任务A和第二个任务B互不影响, 我们可以使用多线程的方法,将任务A和任务B并行执行,最后将两个任务的执行结果相加。那这样怎么用java实现呢?
Futrue接口
- FutureTask和callable是用来干什么的?
- FutureTask实现并行计算(FutureTask的使用)
public interface FutureCallable接口{ // 取消任务。传入的参数为表示若任务开始执行了,是否要尝试中断该线程。参数true为进行尝试中断,false为不进行中断。 boolean cancel(boolean mayInterruptIfRunning); // 获取该任务是否被中断了 boolean isCancelled(); // 该任务是否已经完成 boolean isDone(); // 获取该任务的返回值,若任务还未完成则会阻塞。 V get() throws InterruptedException, ExecutionException; // 获取任务的返回值,若任务还未完成则会阻塞。参数为指定的阻塞的最长时间,超时会抛出TimeoutException。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
public interface CallableFutureTask类{ // Callable只有一个call方法,实现的Callable接口的call方法则为我们要执行的异步任务,V为返回值 V call() throws Exception; }
FutureTask类实现了Future和Runnable接口,是我们实现线程异步执行,并能获取执行结果的封装的实现类。FutureTask有两个构造方法:
- FutureTask(Callable< V> callalbe): 通常的构造方法,Callable为异步任务,通过futureTask的get()方法可以阻塞地获取任务的返回值。
- FutureTask(Runnable runnable, V result): runnable为异步任务,result保存了执行结果,当futureTask的get()方法返回的就是result对象。当然,我们若是关心任务是否执行完成而不关心任务的返回值时,可以使用该构造方法。
场景: 我们要计算1+…+10和20+…+30相加的结果,当然可以用a=1+…+10,b=20+…+30,之后resutl=a+b。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class FutrueDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable callable1= new Callable() {
int res = 0;
@Override
public Integer call() throws Exception {
for (int i=0;i<=10;i++)
res += i;
return res;
}
};
Callable callable2= new Callable() {
int res = 0;
@Override
public Integer call() throws Exception {
for (int i=20;i<=30;i++)
res += i;
return res;
}
};
FutureTask task1 = new FutureTask<>(callable1);
FutureTask task2 = new FutureTask<>(callable2);
Thread thread1 = new Thread(task1);
Thread thread2 = new Thread(task2);
thread1.start();
thread2.start();
System.out.println("结果为:"+(task1.get()+task2.get()));
}
}
线程池实现
import java.util.concurrent.*;
public class FutrueDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future future1 = executorService.submit(()->{ // 这里线程池submit执行的是call方法,返回的是FutureTask对象
int res = 0; // 这里用lambda匿名表达式新建了一个Callable的实现
for (int i = 0; i <= 10; i++) {
res += i;
}
return res;
});
Future future2 = executorService.submit(()->{
int res = 0;
for (int i = 20; i <= 30; i++) {
res += i;
}
return res;
});
System.out.println(future1.get() + future2.get());
}
}



