[Java特性]多线程实现

Java多线程实现的三种方式:继承Thread类,实现Runnable接口,实现Callable接口并用FutureTask类包装

进程与线程

实质是资源的轮流抢占,同一时间点上只有一个程序,同一时间段有多个程序并发
线程是进程基础上划分更小的单元,多线程并发处理执行效率高于进程

多线程的实现

多线程均由用户自定义线程类,优先考虑Runnable接口实现,避免单继承写死,从而更好扩充功能;均通过Thread类的start()方法启动线程;通过Callable接口获取线程返回值
若仅调用run()方法而未调用start()方法,相当于普通方法按顺序执行

单继承实现 Thread类实现多线程

  • 定义 定义用户自定义线程类
public class CustomThread extends Thread{
    //构造方法
    public CustomThread(){}
    //线程主方法
    public void run(){
        //并发运行的内容
    }
}
  • 使用 使用start()方法启动线程
public static void main(String[] args){
    new CustomThread().start();
}

突破单继承局限 Runnable接口实现多线程

Runnable接口定义

@FunctionalInterface  //引入lambda表达式后成为函数式接口
public interface Runnable{
    public void run();
}
  • 定义 定义用户自定义线程类
class CustomThread implements Runnable{
    //构造方法
    public CustomThread(){}
    //线程主方法
    public void run(){
        //并发运行的内容
    }
}
  • 使用1 Runnable接口对象传递给Thread类,再由Thread类调用start()方法
public static void main(String[] args){
    new Thread(new CustomThread()).start();
}
  • 使用2 lambda表达式定义使用
Runnable run = ()-> {
    //并发运行的内容
};
new Thread(run).start();
  • 使用3 lambda表达式定义使用
new Thread(()->{
    //并发运行的内容
}).start();

获取线程返回值 Callable接口实现多线程

Callable接口定义

@FunctionalInterface
public interface Callable<V>{
    public V call() throws Exception;
}

设置一个泛型,此泛型为返回数据的类型,以避免向下转型安全隐患

  • 定义 用户自定义线程类
class CustomThread implements Callable<T> {
    @Override
    public T call() throws Exception{
        //返回值存入T类型对象逻辑
        return T;//返回T类型对象
    }
}
  • 使用
public static void main(String[] args) throws Exception{
    //Callable子类对象传入FutureTask类
    FutureTask<T> task = new FutureTask<>(new CustomThread());
    //FutureTask类对象传入Thread类
    new Thread(task).start();
    //获取返回值
    task.get();
}

Thread类和Runnable类的关系

Thread类和用户自定义CustomThread类都是Runnable接口的子类,实现时均覆写的是Runnable类的run()方法
实际在使用时,run()方法不能被直接调用,测试类调用的是Thread类的start()方法启动线程,start()方法再去调用CustomThread类的run()方法。Thread类的功能是操作系统线程相关的资源调度处理(源码分析1),用户自定义CustomThread类来实现并发进行的核心业务

  • 源码分析
    Thread类的start()方法调用native start0()抽象方法,由JVM根据不同的操作系统来实现start0()(JNI),从而通过不同的操作系统调用各自对应的资源调度算法

    Thread类构造方法传递Runnable接口对象,接口对象被Thread类对象中的target保存
  • 注意
    每个线程的类对象只允许启动一次,同一个线程重复使用start方法抛出IllegalThreadStateException

    • 使用同一用户自定义线程对象,实质是多个Thread类实例化对象并发访问同一自定义线程资源
        class CustomThread implements Runnable {
    
            private int ticket = 5;
    
            @Override
            public void run() {
                while(ticket > 0)
                System.out.println(ticket--);
            }
        }
    
        public static void main(String[] args) {
            CustomThread thread = new CustomThread();
            new Thread(thread).start();
            new Thread(thread).start();
            new Thread(thread).start();
        }
    
        > 执行结果 5 4 3 1 2
    

    • 使用不同自定义线程对象,实质是每个自定义线程对应的Thread类对象访问各自自定义线程中的资源,争抢运行资源并发执行
        class CustomThread implements Runnable {
    
            String name;
            private int ticket = 3;
    
            public CustomThread(String name) {
                this.name = name;
            }
    
            @Override
            public void run() {
                while(ticket > 0)
                    System.out.println(name + ticket--);
            }
        }
    
        public static void main(String[] args) {
            new Thread(new CustomThread("A")).start();
            new Thread(new CustomThread("B")).start();
            new Thread(new CustomThread("C")).start();
        }
    
        > 执行结果 C3 A3 A2 A1 B3 B2 B1 C2 C1
    

Callable类和Runnable类的关系

  • 源码分析




    继承关系图解

    Future接口
/* get()方法实现返回值接收 */
public V get()
throws InterruptedException,ExecutionException;
}

FutureTask接收Callable子类对象,Callable封装在FutureTask中传入Thread类中实现调用

  • Runnable和Callable的区别
    Runnable是JDK1.0提出的,Callable是JDK1.5提出的
    Runnable接口中只有run()方法,无返回值
    Callable接口中只有call()方法,有返回值

线程运行状态




使用start()方法后,线程并未立即执行,而是进入就绪状态,等待资源调度
资源调度成功后进入运行状态,执行run()方法,执行一段时间后让出资源进入阻塞状态,直到再次资源调度成功再进入就绪状态
run()方法执行完毕后,线程进入停止状态

“[Java特性]多线程实现”的一个回复

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

©2018-2024 Howell版权所有 备案号:冀ICP备19000576号