一、方式一:通过实现 Runnable 接口来创建线程(最常用)(无返回值,需要执行完返回就要调用回调接口)
- 1、实现Runnable接口
- 2、重写run方法(具体的实现)
- 3、创建Runnable实现类的实例,并以此实例作为Thread的target对象,即该Thread对象才是真正的线程对象。
- 4、调用Thread的start方法,启动线程。实际通过jvm执行重写的run方法
public class CreateRunnableTest implements Runnable {
private String threadName;
CreateRunnableTest(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
@Override
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public static void main(String[] args){
CreateRunnableTest R1 = new CreateRunnableTest( "Runnable-1");
Thread t1 = new Thread (R1);
t1.start();
CreateRunnableTest R2 = new CreateRunnableTest( "Runnable-2");
Thread t2 = new Thread (R2);
t2.start();
}
}
二、 方式二:通过继承Thread来创建线程(无返回值,需要执行完返回就要调用回调接口)
- 1、创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
- 2、继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
- 3、该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
package com.mls.test.thread;
public class CreateThreadTest<main> extends Thread{
private String threadName;
CreateThreadTest(String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
@Override
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public static void main(String[] args){
CreateThreadTest T1 = new CreateThreadTest( "Thread-1");
T1.start();
CreateThreadTest T2 = new CreateThreadTest( "Thread-2");
T2.start();
}
}
三、方式三:通过 Callable 和 Future 创建线程
-
- 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
-
- 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
-
- 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
-
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
》》应用场景:当父线程想要获取子线程的运行结果时。前两种需要通过回调来获取执行结果。(有返回值,调用获取返回会阻塞)
》》总结:实现Callable和实现Runnable类似,但是功能更强大,具体表现在
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
- 1、可以在任务结束后提供一个返回值,Runnable不行
- 2、call方法可以抛出异常,Runnable的run方法不行
- 3、可以通过运行Callable得到的Future对象监听目标线程调用call方法的结果,得到返回值,(future.get(),调用后会阻塞,直到获取到返回值)
public class CreateCallableTest implements Callable<Integer> {
private int age;
CreateCallableTest(int age){
this.age = age;
}
/**
* 第一步 :注意Callable参数是泛型,传入什么对象,call的返回值就是什么对象
* @return
* @throws Exception
*/
@Override
public Integer call() throws Exception{
System.out.println(Thread.currentThread().getName() +" call function exec start!");
System.out.println(Thread.currentThread().getName() + " param age :" + age);
int i = 999;
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() +" call function exec end!");
return i;
}
public static void main(String[] args) {
for(int i = 0;i < 10;i++) {
CreateCallableTest ctt = new CreateCallableTest(i);//第二步-1
FutureTask<Integer> ft = new FutureTask<>(ctt);//第二步-2
System.out.println(Thread.currentThread().getName()+" 线程的循环变量i的值"+i +" start");
new Thread(ft,"Callable有返回值的线程"+i).start();//第三步
System.out.println(Thread.currentThread().getName()+" 线程的循环变量i的值"+i +" end");
try {
//第四步 (区别前两种的方式,可以获取子线程返回值)fulture.get(),调用后会阻塞,直到获取到返回值,相当于循环顺序调用了
// 所以真用多线程这个没啥用
//System.out.println("Callable子线程的返回值"+ft.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
四、方式四:线程池 (跟数据库连接池类似,避免了线程的创建和销毁造成的额外开销)
- 1、使用Executors工具类中的方法创建线程池
- 2、创建线程实例,可以是Runnable的实现类,也可以是Callable的实现类
- 3、使用线程池对象的submit方法,为线程池中的线程分配任务
- java.util.concurrent
- Executor 负责现成的使用和调度的根接口
-
|--ExecutorService 线程池的主要接口
-
|--ThreadPoolExecutor 线程池的实现类
-
|--ScheduledExecutorService 接口,负责线程的调度
-
|--ScheduledThreadPoolExecutor (extends ThreadPoolExecutor implements ScheduledExecutorService)
- Executors工具类:提供了创建线程池的方法
public class CreateThreadPoolTest { public static void main(String[] args){ //使用Executors工具类中的方法创建线程池 ExecutorService pool = Executors.newFixedThreadPool(5); //创建线程实例,可以是Runnable的实现类,也可以是Callable的实现类 ThreadPoolDemo demo = new ThreadPoolDemo(); //为线程池中的线程分配任务,使用submit方法,传入的参数可以是Runnable的实现类,也可以是Callable的实现类 for(int i=1;i<=5;i++){ pool.submit(demo); } //关闭线程池 //shutdown : 以一种平和的方式关闭线程池,在关闭线程池之前,会等待线程池中的所有的任务都结束,不在接受新任务 //shutdownNow : 立即关闭线程池 pool.shutdown(); } static class ThreadPoolDemo implements Runnable{ /**多线程的共享数据(全局变量)*/ private int i = 0; @Override public void run() { // int m = 1; System.out.println(Thread.currentThread().getName()+"---i="+ i++); //System.out.println(Thread.currentThread().getName()+"---m="+ m++); } }
}
```