热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java多线程的实现方式有哪些

这篇文章主要介绍“Java多线程的实现方式有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java

这篇文章主要介绍“Java多线程的实现方式有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java多线程的实现方式有哪些”文章能帮助大家解决问题。

一、前言

Java多线程实现的三种方式有继承Thread类,实现Runnable接口,使用ExectorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。

二、继承Thread类实现多线程

1.Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。

2.start()方法是一个native方法,它将启动一个新线程,并执行run()方法

3.这种方式实现多线程很简单,通过自己的类直接extend Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法

class MyThread extends Thread{
    public void run(){
        System.out.println("My Thread.run()");
    }
}

启动线程:

MyThread myThread1 = new MyThread();
myThread1.start();

三、Runnable接口方式实现多线程

Java程序里面对于继承永远都是存在有单继承局限的,如果自己的类已经extends另一个类,就无法直接extends Thread,Java里面又提供第二种多线程的主体定义结构形式:实现java.lang.Runnable接口

定义:

@FunctionalInterface    // 从JDK1.8引入了Lambda 表达式之后就变为了函数式接口
public interface Runnable {
  public void run();
}

实现一个Runnable接口:

public class MyThread extends OtherClass implements Runnable {
  public void run() {
   System.out.println("MyThread.run()");
  }
}

启动MyThread,首先实例化一个Thread,并传入自己的MyThread实例:

MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();

当传入一个Runnable target参数给Thread后,Thread的run()方法就会调用target.run()

public void run() {
  if (target != null) {
   target.run();
  }
}

四、Thread和Runnable的关系

1.从代码的结构本身来讲肯定使用Runnable是最方便的,因为其可以避免单继承的局限,同时也可以更好的进行功能的扩充

2.从结构上观察Thread与Runnable的联系

 public class Thread extends Object implements Runnable{}
Thread类也是Runnable 接口的子类,那么在之前继承Thread类的时候实际上覆写的还是Runnable的方法。

3.进行Thread启动多线程时调用的是start()方法,而后找到的是run()方法。当通过Thread类的构造方法传递了一个Runnable接口对象的时候,该接口对象将被Thread中的target的属性保存,在start()方法执行的时候会调用Thread类的run方法,而这个run()方法去调用Runnable接口子类被覆写过的run()方法。

多线程开发的本质实质上是在于多个线程可以进行统一资源的抢占,那么Thread主要描述的是线程,那么资源的描述是通过Runnable完成的。

五、使用ExecutorService、Callable、Future实现有返回结果的多线程

1.ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类

2.返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口

3.执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object,再结合线程池接口ExecutorService就可以实现有返回结果的多线程了

Runnable接口有一个缺点:当线程执行完毕后,我们无法获取一个返回值,所以从JDK1.5之后就提出了一个新的线程实现接口:java.util.concurrent.Callable接口

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

Callbale定义的时候可以设置一个泛型,此泛型的类型就是返回数据的类型

Callable接口和Runnable接口是类似的,但是需要实现的是call方法,而且从上面的代码中我们可以看到run()方法执行的任务是没有返回值的,但是call方法有返回值,可以自定义返回值的类型,这就是两个接口最大的区别

例子:

import java.util.concurrent.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
 
/**
* 有返回值的线程
*/
@SuppressWarnings("unchecked")
public class Test {
	public static void main(String[] args) throws ExecutionException,
	   InterruptedException {
	   System.out.println("----程序开始运行----");
	   Date date1 = new Date();
	 
	   int taskSize = 5;
	   // 创建一个线程池
	   ExecutorService pool = Executors.newFixedThreadPool(taskSize);
	   // 创建多个有返回值的任务
	   List list = new ArrayList();
	   for (int i = 0; i < taskSize; i++) {
	    Callable c = new MyCallable(i + " ");
	    // 执行任务并获取Future对象
	    Future f = pool.submit(c);
	    // System.out.println(">>>" + f.get().toString());
	    list.add(f);
	   }
	   // 关闭线程池
	   pool.shutdown();
	 
	   // 获取所有并发任务的运行结果
	   for (Future f : list) {
	    // 从Future对象上获取任务的返回值,并输出到控制台
	    System.out.println(">>>" + f.get().toString());
	   }
	 
	   Date date2 = new Date();
	   System.out.println("----程序结束运行----,程序运行时间【"
	     + (date2.getTime() - date1.getTime()) + "毫秒】");
	}
}
 
class MyCallable implements Callable {
	private String taskNum;
	 
	MyCallable(String taskNum) {
	   this.taskNum = taskNum;
	}
	 
	public Object call() throws Exception {
	   System.out.println(">>>" + taskNum + "任务启动");
	   Date dateTmp1 = new Date();
	   Thread.sleep(1000);
	   Date dateTmp2 = new Date();
	   long time = dateTmp2.getTime() - dateTmp1.getTime();
	   System.out.println(">>>" + taskNum + "任务终止");
	   return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
	}
}

关于“Java多线程的实现方式有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程笔记行业资讯频道,小编每天都会为大家更新不同的知识点。


推荐阅读
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 阅读spring5源码DefaultSingletonBeanRegistry类遇到问题发现SpringBean中存在大量回调机制和aware接口,于是特意去了解 ... [详细]
  • java线程池的实现原理源码分析
    这篇文章主要介绍“java线程池的实现原理源码分析”,在日常操作中,相信很多人在java线程池的实现原理源码分析问题上存在疑惑,小编查阅了各式资 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了在Java中gt、gtgt、gtgtgt和lt之间的区别。通过解释符号的含义和使用例子,帮助读者理解这些符号在二进制表示和移位操作中的作用。同时,文章还提到了负数的补码表示和移位操作的限制。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • C++中的三角函数计算及其应用
    本文介绍了C++中的三角函数的计算方法和应用,包括计算余弦、正弦、正切值以及反三角函数求对应的弧度制角度的示例代码。代码中使用了C++的数学库和命名空间,通过赋值和输出语句实现了三角函数的计算和结果显示。通过学习本文,读者可以了解到C++中三角函数的基本用法和应用场景。 ... [详细]
  • 本文介绍了协程的概念和意义,以及使用greenlet、yield、asyncio、async/await等技术实现协程编程的方法。同时还介绍了事件循环的作用和使用方法,以及如何使用await关键字和Task对象来实现异步编程。最后还提供了一些快速上手的示例代码。 ... [详细]
author-avatar
自由飘落de花瓣
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有