在Java中要想实现多线程代码有两种方法,一种是继承 Thread 类,另一种就是实现 Runnable 接口

一、继承 Thread 类

Thread 类是在 java.lang 包中定义的,一个类只要继承了 Thread 类,此类就称为多线程操作类。

在 Thread 子类中,必须明确地覆写 Thread 类中的 run() 方法,此方法为线程的主体

例子:继承Thread类实现多线程

  1. class MyThread extends Thread { //继承Thread类
  2. private String name;
  3. public MyThread(String name) {
  4. this.name = name;
  5. }
  6. public void run() { //覆写Thread类中的run 方法
  7. for(int i=0;i<5;i++){
  8. System.out.println(name + " 运行:i = " + i);
  9. }
  10. }
  11. }
  12. public class ThreadDemo {
  13. public static void main(String[] args) {
  14. MyThread mt1 = new MyThread("线程A");
  15. MyThread mt2 = new MyThread("线程B");
  16. mt1.run();
  17. mt2.run();
  18. }
  19. }

程序运行结果

  1. 线程A 运行:i = 0
  2. 线程A 运行:i = 1
  3. 线程A 运行:i = 2
  4. 线程A 运行:i = 3
  5. 线程A 运行:i = 4
  6. 线程B 运行:i = 0
  7. 线程B 运行:i = 1
  8. 线程B 运行:i = 2
  9. 线程B 运行:i = 3
  10. 线程B 运行:i = 4

发现以上的程序是先执行完mt1对象之后再执行mt2对象,并没有交错运行,也就是说,此时线程实际上并没有被启动,

还是属于顺序式的执行方式,那么该如何启动线程呢?如果要正确地启动线程,是不能直接调用run()方法的,而应该

是调用从 Thread 类中继承而来的 start() 方法,具体代码如下:

例子:启动线程

  1. class MyThread extends Thread { //继承Thread类
  2. private String name;
  3. public MyThread(String name) {
  4. this.name = name;
  5. }
  6. public void run() { //覆写Thread类中的run 方法
  7. for(int i=0;i<5;i++){
  8. System.out.println(name + " 运行:i = " + i);
  9. }
  10. }
  11. }
  12. public class ThreadDemo {
  13. public static void main(String[] args) {
  14. MyThread mt1 = new MyThread("线程A");
  15. MyThread mt2 = new MyThread("线程B");
  16. mt1.start(); //启动多线程
  17. mt2.start();
  18. }
  19. }

程序运行结果(可能的一种结果)

  1. 线程A 运行:i = 0
  2. 线程B 运行:i = 0
  3. 线程A 运行:i = 1
  4. 线程B 运行:i = 1
  5. 线程A 运行:i = 2
  6. 线程B 运行:i = 2
  7. 线程A 运行:i = 3
  8. 线程B 运行:i = 3
  9. 线程A 运行:i = 4
  10. 线程B 运行:i = 4

从程序的运行结果中可以发现,两个线程现在是交错运行的,哪个线程对象抢到了CPU资源,哪个线程就可以运行,

所以程序每次的运行结果是不一样的,在线程启动时虽然调用的是start()方法,但实际上调用的却是run()方法的主体

二、实现 Runnable 接口

在Java中也可以通过实现 Runnable 接口的方式实现多线程,Runnable 接口中只定义了一个抽象方法: public void run();

例子:实现Runnable接口

  1. class MyThread implements Runnable { //实现Runnable接口
  2. private String name;
  3. public MyThread(String name) {
  4. this.name = name;
  5. }
  6. public void run() { //覆写Runnable类中的run 方法
  7. for(int i=0;i<5;i++){
  8. System.out.println(name + " 运行:i = " + i);
  9. }
  10. }
  11. }

以上代码通过实现Runnable接口实现多线程,从之前代码中可以知道,要想启动一个多线程必须要使用start()方法完成

如果继承了Thread类,则可以直接从Thread类中使用start()方法 但是现在实现的是Runnable接口,该如何启动多线程呢?

实际上,此时还是要依靠Thread类完成启动,在Thread类中提供了

public Thread(Runnable target)public Thread(Runnable target,String name) 两个构造方法

这两个构造方法都可以接收Runnable的子类实例对象,所以就可以依靠此点启动多线程

例子:使用Thread类启动多线程

  1. class MyThread implements Runnable { //实现Runnable接口
  2. private String name;
  3. public MyThread(String name) {
  4. this.name = name;
  5. }
  6. public void run() { //覆写Runnable类中的run 方法
  7. for(int i=0;i<5;i++){
  8. System.out.println(name + " 运行:i = " + i);
  9. }
  10. }
  11. }
  12. public class ThreadDemo {
  13. public static void main(String[] args) {
  14. MyThread mt1 = new MyThread("线程A"); //实例化Runnable子类对象
  15. MyThread mt2 = new MyThread("线程B");
  16. Thread t1 = new Thread(mt1); //实例化Thread类对象
  17. Thread t2 = new Thread(mt2);
  18. t1.start(); //启动线程
  19. t2.start();
  20. }
  21. }

程序运行结果

  1. 线程B 运行:i = 0
  2. 线程A 运行:i = 0
  3. 线程B 运行:i = 1
  4. 线程A 运行:i = 1
  5. 线程B 运行:i = 2
  6. 线程B 运行:i = 3
  7. 线程A 运行:i = 2
  8. 线程B 运行:i = 4
  9. 线程A 运行:i = 3
  10. 线程A 运行:i = 4

从以上两种实现可以发现,无论使用哪种方式,最终都必须依靠Thread类才能启动多线程

三、Thread类和Runnable接口

通过Thread类和Runnable接口都可以实现多线程,那两者有哪些联系和区别呢,下面观察Thread类的定义

public class Thread extends Object implements Runnable

从Thread类的定义可以发现,Thread类也是Runnable接口的子类。实际上Thread类和Runnable接口之间在使用上也是

有区别的,如果一个类继承Thread类,则不适合于多个线程共享资源,而实现了Runnable接口,就可以方便地实现资源的共享。

例子:继承Thread类不能资源共享

  1. class MyThread extends Thread { // 继承Thread类
  2. private int ticket = 5; //一共5张票
  3. public void run() { // 覆写run 方法
  4. for (int i = 0; i < 100; i++) {
  5. if(ticket > 0){ //判断是否有剩余票
  6. System.out.println("卖票:ticket = " + ticket--);
  7. }
  8. }
  9. }
  10. }
  11. public class ThreadDemo {
  12. public static void main(String[] args) {
  13. MyThread mt1 = new MyThread();
  14. MyThread mt2 = new MyThread();
  15. MyThread mt3 = new MyThread();
  16. mt1.start(); //启动线程
  17. mt2.start();
  18. mt3.start();
  19. }
  20. }

程序运行结果

  1. 卖票:ticket = 5
  2. 卖票:ticket = 5
  3. 卖票:ticket = 5
  4. 卖票:ticket = 4
  5. 卖票:ticket = 4
  6. 卖票:ticket = 3
  7. 卖票:ticket = 4
  8. 卖票:ticket = 2
  9. 卖票:ticket = 3
  10. 卖票:ticket = 1
  11. 卖票:ticket = 3
  12. 卖票:ticket = 2
  13. 卖票:ticket = 2
  14. 卖票:ticket = 1
  15. 卖票:ticket = 1

以上程序通过Thread类实现多线程,程序中启动了三个线程,但三个线程却分别卖了各自的5张票,

并没有达到资源共享的目的。

例子:实现Runnable接口可以实现资源共享

  1. class MyThread implements Runnable { // 实现Runnable接口
  2. private int ticket = 5; //一共5张票
  3. public void run() { // 覆写run 方法
  4. for (int i = 0; i < 100; i++) {
  5. if(ticket > 0){ //判断是否有剩余票
  6. System.out.println("卖票:ticket = " + ticket--);
  7. }
  8. }
  9. }
  10. }
  11. public class ThreadDemo {
  12. public static void main(String[] args) {
  13. MyThread mt = new MyThread();
  14. new Thread(mt).start(); //启动线程
  15. new Thread(mt).start();
  16. new Thread(mt).start();
  17. }
  18. }

程序运行结果

  1. 卖票:ticket = 5
  2. 卖票:ticket = 3
  3. 卖票:ticket = 4
  4. 卖票:ticket = 1
  5. 卖票:ticket = 2

从程序的运行结果中可以发现,虽然启动了3个线程,但是3个线程一共才卖了5张票,即ticket属性被所有的线程对象共享

可见,实现 Runnable 接口相对于继承Thread类来说,有如下显著的优势:

  • 适合多个相同程序代码的线程去处理同一资源的情况。

  • 可以避免由于Java的单继承特性带来的局限

  • 增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。

所以,在开发中建议使用 Runnable 接口实现多线程

作者:itmyhome

Java中线程的实现的更多相关文章

  1. java中线程分两种,守护线程和用户线程。

    java中线程分为两种类型:用户线程和守护线程. 通过Thread.setDaemon(false)设置为用户线程: 通过Thread.setDaemon(true)设置为守护线程. 如果不设置次属性 ...

  2. java中线程机制

    java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...

  3. Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞

    Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...

  4. Java中线程的实现:

    Java中线程的实现: 一.线程简介: 实现的两种方式为: 1.Thread类 2.Runnable接口 都在java.lang中 都有共通的方法:public void run() 二.线程常用方法 ...

  5. JAVA中线程同步方法

    JAVA中线程同步方法 1  wait方法:         该方法属于Object的方法,wait方法的作用是使得当前调用wait方法所在部分(代码块)的线程停止执行,并释放当前获得的调用wait所 ...

  6. 多线程(三) java中线程的简单使用

    java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...

  7. Java中线程池,你真的会用吗?

    在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...

  8. Java中线程同步的理解 - 其实应该叫做Java线程排队

    Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可 ...

  9. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  10. Java中线程和线程池

    Java中开启多线程的三种方式 1.通过继承Thread实现 public class ThreadDemo extends Thread{ public void run(){ System.out ...

随机推荐

  1. iOS 音频/视频 学习目录

    参考 iOS原生API  音/视频录制 编辑 https://www.cnblogs.com/kenshincui/p/4186022.html#summary iOS视频编解码常用库比较 http: ...

  2. python脚本中appium的自启动自关闭

    前提:已安装appium命令行版本 将appium的启动及其关闭直接写在脚本中,运行起来会方便很多 创建startAppiumServer.bat 和 stopAppiumServer.bat文件,然 ...

  3. Angular material mat-icon 资源参考_Hardware

    ul,li>ol { margin-bottom: 0 } dt { font-weight: 700 } dd { margin: 0 1.5em 1.5em } img { height: ...

  4. docker 容器container运行后,如何进入容器内部?

    docker exec -ti  容器ID  /bin/bash

  5. 【算法笔记】B1051 复数乘法

    题目链接:https://pintia.cn/problem-sets/994805260223102976/problems/994805274496319488 思路: 难点在于对复数其他形式的认 ...

  6. POJ_2155 Matrix 【二维树状数组】

    一.题面 POJ2155 二.分析 楼教主出的题,是二维树状数组非常好的题,还结合了开关问题(开关变化的次数如果为偶数,状态不变,奇数状态相反). 题意就是给了一个二维的坐标平面,每个点初始值都是0, ...

  7. springcloud(三)-Eureka

    Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现.也是springcloud体系中最重要最核心的组 ...

  8. linux vi文本编辑器三种模式切换及常用操作

    初学者刚进入vi不要乱点键盘,vi的三种模式和各种命令很容易弄混@@ vi编辑器是Unix系统最初的编辑器.它使用控制台图形模式来模拟文本编辑窗口,允许查看文件中的行.在文件中移动.插入.编辑和替换文 ...

  9. Java - 关于子类父类的向上转型,向下转型

    以下Animal为父类,Dog,Cat作为子类,分别继承Animal class Animal{ public void shout(){ System.out.println("叫了一声& ...

  10. ionic3打包打包安卓apk详细过程以及遇到的问题

    1.jdk和sdk的安装以及环境变量配置参考打包详解 上述连接已经从下载安装jdk以及sdk的环境变量配置到打包的流程以及很详细了.但是在我自己安装打包的过程中遇到了这篇文章中没有遇到的问题,下面图文 ...