- 创建线程
在Java中使用Thread类表示线程,每一个线程都是Thread类的对象或者子类的对象,相当于Thread类是所有线程的父类,所有的线程对象都是一个任务,需要调度器安排序列被CPU执行,在使用了Thread类时,这些线程对象会被同时执行;
实现创建线程的方式:继承Thread类、实现Runnable接口、实现Callable接口、使用线程池。
1.1 继承Thread类
- 多线程的启动方式:
- 自定义线程类继承Thread类;
- 重写run()方法;
- 创建线程对象并使用调用start()方法开启线程;
2. 在使用过程中run()方法只是重写,不需要调用,start()就是调用run()方法;
3. Thread类常用方法:
- run()方法:
- Run方法在执行时必须要重写,返回值为void类型;
- start()方法:
- 启动线程,执行run()方法中内容,返回类型为void类型;
- currentThread()方法:
- 返回当前线程,返回类型为Thread类型,一般调用该方法后还需调用其他方法结合使用,例:thread.currentThread().getName();该语句时返回当前对象thread的线程中的线程名称;
- getName()方法:
- 获取该线程的名称,返回类型为String类型;
- setName()方法:
- 设置线程名称,返回类型为void类型;
- sleep()方法:
- 该sleep(long millis)为使当前线程睡眠阻塞,睡眠阻塞时间millis类型为long类型,单位是毫秒;
- 在睡眠过程中不占用cpu,空余线程分配给其他线程使用cpu,当前线程睡眠后重新到调度器中排队执行;
- 注意:
- 在springboot框架中使用sleep()方法时,需有抛出异常处理,一般对其使用InterruptedException抛出异常,使用try-catch语句处理抛出异常语句;但在springboot中使用注解@SnackThrows即可;
- 每个对象都有一个锁,sleep不会释放锁;
- join()方法:
- join合并线程,待此线程执行完毕后再执行其他线程,其他线程阻塞(即插队执行该线程);
- 在当线程a中的调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完毕,线程才结束阻塞,继续执行。
- 例:线程a的运行过程中需要一个参数,这个参数需要线程b提供,这时,就需要join()方法;
- 在springboot框架中使用join()方法时,需有抛出异常处理,一般对其使用InterruptedException抛出异常,使用try-catch语句处理抛出异常语句;但在springboot中使用注解@SnackThrows即可
- isAlive()方法:
- 判断线程是否还活着,返回类型是boolean类型;
- setPriority()和getPriority()方法:
- 设置线程的优先级和获取线程优先级;返回类型为int类型;1-10表示优先级,优先级越高数字越大,不设置优先级自动默认优先级为5;
- 注意:优先级越大抢占CPU概率越大,优先级越大不一定CPU先执行该线程;
- 例:已有一个线程Thread对象thread,thread.setPriority(1)、thread.getPriority()
setDaemon()方法:
- 设置守护线程,当其他非守护线程执行完毕后守护线程陆续结束;thread.setDaemon(false);这个方法默认为false,当为false情况下,外面主线程运行结束,停了,开启的子线程依然在跑。thread.setDaemon(true);当为守护线程的时候,外面主方法结束,主方法开启的子线程守护线程就会结束。
- 例:把Thread类对象thread1设置为守护线程,thread.setDaemon(true)
yield()方法:
- 礼让线程,让当正在执行的线程暂停,但不阻塞,礼让后线程重新回到初始状态,多个线程同时竞争CPU,礼让不一定成功;
- 需要用类Thread.yield()方法启用;
1.2实现Runnable()接口(重点)
- 多线程启动方法:
- 自定义一个类实现Runnable接口;
- 重写run()方法;
- 创建线程对象,调用start()方法启动线程;
2. 方法:(和继承Thread方法类似)
3. 优化代码:
例:
使用RunnableDemo类实现Runnable接口;
RunnableDemo runableDemo = new RunnableDemo();
Thread thread = new Thread(RunnableDemo);
thread.setName(“aaa”);
thread.start();
优化后:
RunnableDemo runnabledemo = new RunnableDemo();
new Thread(runnableDemo , “aaa”).start();
注意:
实现Runnable接口与继承Thread类的异同在于:
- 不同点:实现Runable接口方式实现它的类可能还继承了其他父类,在Java中只能有一个继承父类,若再继承Thread类则冲突,故再使用过程中建议使用实现Runnable接口使用多线程;
- 相同点:都需要重写run()方法;
-
Runnable接口的优点:
避免单继承的局限,灵活方便,方便同一个对象被多个线程使用;
1.3实现Callable()接口
- 多线程启动方法:
- 自定义一个类实现Callable接口;
- 重写call()方法;
- 创建线程对象;
方法一:
- 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
- 此处newFixedThreadPool(1)的“1”表示有一个线程;
- 执执行提交:Future<T> result1 = ser.submit(t1);
- 获取结果:boolean r1 = result1.get();
- 关闭服务:ser.shutdownNow();
方法二:
- 创建FutureTask对象:FutureTask<T> futureTask = new FutureTask<>(线程对象);
- 创建Thread对象:Thread thread = new Thread(futureTask);
- 开启线程:thread.start();
对比:
Callable接口可以实现多线程运行的结果,返回一个boolean类型
注意:
在自定义类继承implements Callable接口时,需要注意后必须跟一个泛型类,该泛型类的类型可以自定义,pubic class MyCallable implements Callable<T>
例:pubic class MyCallable implements Callable<Integer>{
该泛型类在使用过程中决定了call()方法的返回类型;
@Override
Public Integer call(){
1.4 三种方法优缺点:
方法 | 优点 | 缺点 |
继承Thread类 | 可以直接使用Thread类中方法; | 不可继承其他类,可实现的扩展性差 |
实现Runnable接口 | 可继承其他类,实现接口功能 | 不能直接使用Thread类中的方法,没有返回值; |
实现Callable接口 | 可继承其他类,实现接口功能;有返回值且返回类型可自定义; | 不能直接使用Thread类中的方法 |