Java多线程——多线程的四种实现方式

本文介绍了Java中实现多线程的四种主要方法:继承Thread类、实现Runnable接口、实现Callable接口以及使用线程池。详细解释了每种方法的特点、适用场景及其实现方式,并强调了启动线程时必须使用start()方法。

Java多线程——多线程的四种实现方式

前言:

  本篇文章有几个必要重要的知识点
   1、启动线程的注意事项
   2、继承Thread类与实现Runnable接口的关系
   3、Callable与Thread、Runnable的关系

一、直接继承Thread,覆写run()方法

		class MyThread1 extends Thread{
		    private String title;
		
		    public MyThread1(String title){
		        this.title = title;
		    }
		
		    @Override
		    public void run() {
		        for (int i = 0;i<10;i++) {
		            System.out.println(title+":"+i);
		        }
		    }
		}
  这里覆写的run()方法相当于主线程的main()方法,是一个线程的入口方法。
  启动线程的注意事项(具体流程请参考:线程启动函数start()源码解析
   1、无论是哪种方式实现多线程,线程启动一定调用Thread类提供的start()方法<而不是run()方法>
   2、线程start()方法只能调用一次,再次调用就会抛出线程非法状态(启动)异常(java.lang.IllegalThreadStateException)
   3、start()方法的具体流程:start(判断当前线程是不是首次创建,Java方法)->调用start0()方法(JVM)->通过JVM进行资源调度,系统分配->回调run()方法(Java方法)执行线程的具体操作任务。
   4、run()方法与start()的区别:如果线程直接调用run()方法,当且仅当run()只是一个普通方法;如果线程是通过start()方法(JVM回调)调用的run()方法,则可以实现线程的开启。

二、实现Runnable接口,覆写run()方法

  由于在Java语言中,类具有单继承局限,因此实现Runnable接口可以使得:多个线程共享一个Runnable对象,通过实现Runnable接口的方式实现多线程更能体现出“共享”的概念(创建一个Runnable接口对象,并传入到多个new Thread(Runnable)中)
		class MyRunnable implements Runnable{
		
		    private String title;
		    private Integer ticket = 10;
		
		    public MyRunnable(String title){
		        this.title = title;
		    }
		
		    @Override
		    public void run() {
		        for (int i=0;i<10;i++) {
		            System.out.println(this.title+"卖了一张票,还剩"+(ticket--)+"张票");
		        }
		    }
		}
  最终一定要使用start()来开启线程——通过Thread(Runnable),此时的Runnable可以使用匿名内部类/lambda表达式(只有一个run()方法)
		// 调用已存在的Runnable对象启动一个线程
		new Thread(runnable).start();
	
		// 使用匿名内部类启动一个线程
		new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start();

		// 使用lambda表达式启动一个线程(非常简便)
		new Thread(()-> System.out.println(Thread.currentThread().getName())).start();
  继承Thread类与实现Runnable接口的关系

在这里插入图片描述

   1、继承具有单继承局限,而实现接口不限个数。
   2、Thread类与自定义线程类(实现了Runnable接口),是一个典型的代理设计模式,Thread类负责辅助真实业务操作(资源调度,创建线程并启动),自定义线程类负责真实业务的实现(run方法具体要做啥事)
   3、使用Runnable接口实现的多线程程序类可以更好的描述共享的概念。多个线程可以共同享用一个Runnable对象。

三、实现Callable接口,覆写call()方法

   当线程有返回值时,只能通过实现Callable实现多线程 ,Callable接口在juc(java.util.concurrent)包下。
			// 覆写call()方法,而不是run()方法可
			V call() throws Exception;

  举个栗子

	class MyCallable implements Callable<String>{
	
    	private int ticket = 10;
    	
	    @Override
	    public String call() throws Exception {
	        while(this.ticket>0){
	            System.out.println(Thread.currentThread().getName()+",剩余票数:"+this.ticket--);
	        }
	        return "票卖完了";
	    }
	}
  Callable接口与Thread、Runnable的关系

在这里插入图片描述

   从图中可以看到
   ① Future接口中get()方法的作用是: 取得Callable接口的返回值。
   ②RunnableFuture接口即继承了Runnable接口又继承了Future接口(接口的多继承),因此RunnableFuture接口拥有所继承的所有方法。
   ③ FutureTask(Callable实现多线程的核心类)即是Runnable的子类,又是RunnableFuture的子类,又可以传入Callable(FutureTask的构造方法)——连通三者,因此FutureTask的作用为:
    a)将Callable转为FutureTask
    b)将FutureTask转为Thread(因为FutureTask间接实现了Runnable接口,相当于是Runnable)
    c)使用Thread的start()方法启动线程——兜兜转转启动线程还是只能使用Thread的start()方法
   因此,使用Callable接口的方式启动线程变为了:
	public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 先取得Callable对象
        MyCallable myCallable = new MyCallable();
        
        // 将Callable对象转换为FutureTask对象
        FutureTask<String> futureTask = new FutureTask<>(myCallable);
        
        // 由于FutureTask对象实现了RunnableFuture接口,
        // 而RunnableFuture接口又是Runnable接口的子接口,
        // 因此可以将FutureTask对象当做Runnable接口的实现类传给Thread
        Thread thread1 = new Thread(futureTask);
        Thread thread2 = new Thread(futureTask);
        
        // 一切的一切,最终的最终,开启线程还得是Thread的start方法
        thread1.start();
        thread2.start();

		// 打印线程的返回值
        // 由于FutureTask间接实现了Future接口
        // 因此可以使用FutureTask的get()方法获取线程的返回值
        System.out.println(futureTask.get());
    }

	// 打印结果如下:
	Thread-0,剩余票数:10
	Thread-0,剩余票数:9
	Thread-0,剩余票数:8
	Thread-0,剩余票数:7
	Thread-0,剩余票数:6
	Thread-0,剩余票数:5
	Thread-0,剩余票数:4
	Thread-0,剩余票数:3
	Thread-0,剩余票数:2
	Thread-0,剩余票数:1
	票卖完了              // 线程的返回值

四、线程池

线程池及Executor框架
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值