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

Java基础学习总结多线程的实现

目录:继承Thread类start()方法实现多线程的原理实现Runnable接口Thread类与Runnable接口的联系与区别多线程的实现方法

 

目录:

  •   继承Thread类
  •   start()方法实现多线程的原理
  •   实现Runnable接口
  •   Thread类 与 Runnable接口 的联系与区别

 

  多线程的实现方法:

    继承Thread类

    实现Runnable接口

  -------------------------------------------------------------------------------------

  1. 继承Thread类

    继承Thread类之后,需要覆盖父类的 public void run() 方法,作为线程的主方法。

    所有线程的执行一定是并发的,即:同一个时间段上会有多个线程交替执行。为了达到这样的目的,绝对不能直接调用run()方法,而是应该调用Thread类的start()方法启动多线程。

    调用 start() 方法和调用 run() 方法的对比:

public class MyThread extends Thread {private String name;public MyThread(String name) {this.name &#61; name;}&#64;Overridepublic void run() {for(int i&#61;0; i<10; i&#43;&#43;) {System.out.println(name &#43; "打印&#xff1a;" &#43; i);}}public static void main(String[] args) {MyThread mt1 &#61; new MyThread("线程A");MyThread mt2 &#61; new MyThread("线程B");MyThread mt3 &#61; new MyThread("线程C");mt1.start();mt2.start();mt3.start();}
}

  运行结果&#xff1a;&#xff08;三个线程同时且交替执行&#xff0c;没有固定的执行顺序&#xff09;

   

public class MyThread extends Thread {private String name;public MyThread(String name) {this.name &#61; name;}&#64;Overridepublic void run() {for(int i&#61;0; i<5; i&#43;&#43;) {System.out.println(name &#43; "打印&#xff1a;" &#43; i);}}public static void main(String[] args) {MyThread mt1 &#61; new MyThread("线程A");MyThread mt2 &#61; new MyThread("线程B");MyThread mt3 &#61; new MyThread("线程C");mt1.run();mt2.run();mt3.run();}
}

  运行结果&#xff1a;&#xff08;三个程序依次顺序执行&#xff09;

   

 

  2. start()方法实现多线程的原理

    打开Thread类源代码中start()方法的部分&#xff1a;

public synchronized void start() {if (threadStatus !&#61; 0)throw new IllegalThreadStateException();group.add(this);boolean started &#61; false;try {start0();started &#61; true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}
}
private native void start0();

    native关键字是指调用操作系统的方法&#xff0c;start0()方法是所在操作系统的方法。

    由于线程的启动需要牵扯到操作系统中资源的分配问题&#xff0c;所以具体的线程的启动应该根据不同的操作系统有不同的实现。而JVM根据不同的操作系统中定义的start0()方法进行不同的实现。这样&#xff0c;在多线程的层次上start0()方法的名称不改变&#xff0c;而不同的操作系统有不同的实现。

原理图

    结论&#xff1a;只有Thread类的start()方法才能进行操作系统资源的分配&#xff0c;所以启动多线程的方式永远就是Thread类的start()方法。

 

  3. 实现Runnable接口

    一般使用这种方式来实现多线程&#xff0c;因为这样可以避免继承Thread类的单继承局限

package test;public class MyThread implements Runnable {private String name;public MyThread(String name) {this.name &#61; name;}&#64;Overridepublic void run() {for(int i&#61;0; i<5; i&#43;&#43;) {System.out.println(name &#43; "打印&#xff1a;" &#43; i);}}public static void main(String[] args) {MyThread mt1 &#61; new MyThread("线程A");MyThread mt2 &#61; new MyThread("线程B");MyThread mt3 &#61; new MyThread("线程C");new Thread(mt1).start();new Thread(mt2).start();new Thread(mt3).start();}
}

 

  4. Thread类 与 Runnable接口 的联系与区别

    联系&#xff1a;

      Thread类是实现了Runnable接口的类。

      

    区别&#xff1a;

      Runnable接口实现的多线程要比Thread类实现的多线程更方便的表示出数据共享的概念。

      范例&#xff1a;希望有三个线程进行卖票

//使用Thread类实现public class MyThread extends Thread {private String name;int tickets &#61; 5;public MyThread(String name) {this.name &#61; name;}&#64;Overridepublic void run() {while(tickets>0) {System.out.println(name &#43; "买票出一张票&#xff0c;剩余票数&#xff1a;" &#43; (--tickets));}}public static void main(String[] args) {MyThread mt1 &#61; new MyThread("线程A");MyThread mt2 &#61; new MyThread("线程B");MyThread mt3 &#61; new MyThread("线程C");mt1.start();mt2.start();mt3.start();}
}
/*
线程C买票出一张票&#xff0c;剩余票数&#xff1a;4
线程A买票出一张票&#xff0c;剩余票数&#xff1a;4
线程B买票出一张票&#xff0c;剩余票数&#xff1a;4
线程A买票出一张票&#xff0c;剩余票数&#xff1a;3
线程C买票出一张票&#xff0c;剩余票数&#xff1a;3
线程A买票出一张票&#xff0c;剩余票数&#xff1a;2
线程B买票出一张票&#xff0c;剩余票数&#xff1a;3
线程A买票出一张票&#xff0c;剩余票数&#xff1a;1
线程C买票出一张票&#xff0c;剩余票数&#xff1a;2
线程C买票出一张票&#xff0c;剩余票数&#xff1a;1
线程A买票出一张票&#xff0c;剩余票数&#xff1a;0
线程B买票出一张票&#xff0c;剩余票数&#xff1a;2
线程B买票出一张票&#xff0c;剩余票数&#xff1a;1
线程B买票出一张票&#xff0c;剩余票数&#xff1a;0
线程C买票出一张票&#xff0c;剩余票数&#xff1a;0
*/

//使用Runnable接口实现public class MyThread implements Runnable {int tickets &#61; 5;&#64;Overridepublic void run() {while(tickets>0) {System.out.println(Thread.currentThread().getName() &#43; "买票出一张票&#xff0c;剩余票数&#xff1a;" &#43; (--tickets));}}public static void main(String[] args) {MyThread mt &#61; new MyThread();new Thread(mt,"线程A").start();new Thread(mt,"线程B").start();new Thread(mt,"线程C").start();}
}
/*
线程B买票出一张票&#xff0c;剩余票数&#xff1a;3
线程A买票出一张票&#xff0c;剩余票数&#xff1a;4
线程C买票出一张票&#xff0c;剩余票数&#xff1a;2
线程A买票出一张票&#xff0c;剩余票数&#xff1a;0
线程B买票出一张票&#xff0c;剩余票数&#xff1a;1
*/

//同一个线程不能重复启动&#xff0c;否则会出现异常public class MyThread extends Thread {int tickets &#61; 5;&#64;Overridepublic void run() {while(tickets>0) {System.out.println("买票出一张票&#xff0c;剩余票数&#xff1a;" &#43; (--tickets));}}public static void main(String[] args) {MyThread mt &#61; new MyThread();mt.start();mt.start();mt.start();}
}
/*
Exception in thread "main" 买票出一张票&#xff0c;剩余票数&#xff1a;4
买票出一张票&#xff0c;剩余票数&#xff1a;3
买票出一张票&#xff0c;剩余票数&#xff1a;2
买票出一张票&#xff0c;剩余票数&#xff1a;1
买票出一张票&#xff0c;剩余票数&#xff1a;0
java.lang.IllegalThreadStateExceptionat java.lang.Thread.start(Unknown Source)at test.MyThread.main(MyThread.java:17)
*/

    图释&#xff1a;

   

使用Thread类的内存情况

   

使用Runnable接口的内存情况

  面试题&#xff1a;请解释多线程的两种实现方式以及区别&#xff0c;并用代码验证&#xff1f;

    答&#xff1a;多线程需要一个线程的主类&#xff0c;这个类要么继承Thread类&#xff0c;要么实现Runnable接口&#xff1b;

      使用Runnable接口要比Thread类更好地实现数据共享的操作&#xff0c;并且使用Runnable接口可以避免单继承局限。

      代码如上。

 

 

 

 

转:https://www.cnblogs.com/xingyazhao/p/6083638.html



推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
author-avatar
王丽丽2502934407
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有