首页 > 编程语言 >Java 多线程的创建

Java 多线程的创建

时间:2024-06-03 18:58:46浏览次数:24  
标签:main Java Thread 创建 start 线程 run 多线程 public

Java 多线程的创建

Java元的JVM允许程序运行多个线程,使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类

线程的创建方式有两种,一者为继承Thread类,一者为实现Runnable接口

实现方式之一:继承Thread类

实现步骤

Java通过继承Thread类来创建启动多线程的步骤如下:

  • 创建一个继承于Thread
  • 重写Thread类的run() 将此线程要执行的操作,生命在此方法体中
  • 创建当前Thread 的子类的对象
  • 通过对象调用start() —>1. 启动线程 2.调用当前线程的run()方法

创建一个分线程1,用于遍历100日内的偶数

class PrintNumber extends Thread{
   
   @Override
   重写Thread类中的run()方法  ---->将此线程要执行的操作,声明在方法体中
   public void run() {
       for(int i=0;i<=100;i++){
           if(i % 2 == 0){
               System.out.println(i);
           }
       }
   }
}

public class NumberTest{
   public static void main(String []args){
		//创建当前Thread的子类的对象
       PrintNumber t1 = new PrintNumber();
       //通过对象调用start()方法   start是父类Thread中的方法
       t1.start();
   }
}

//API中start()的描述
//Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
//启动线程,JVM会调用当前线程的run()方法

分线程会和main()并发进行,改动后

public class ThreadTest {
   public static void main(String[] args) {
       OneThread o1 = new OneThread();
       o1.start();
       for(int i = 0; i< 1000000; i++){
           System.out.println("这是main方法");
       }
   }
}

class OneThread extends Thread{
   @Override
   public void run() {
       for (int i = 0; i < 1000000; i++) {
           System.out.println("这是OneThread");
       }
   }
}
//当运行此程序时,输出为
//这是main方法 与 这是OneThread 交叉输出 
//也可以使用Thread.currentThread().getName()直观的输出 该线程的名称

深入思考

问题一

run()方法已经重写,并且run()方法中是分线程所需要执行的操作,那能否使用run()方法替换start()方法的调用,实现分线程的创建和调用?

不能,如果这样使用,则不会创建多线程,就相当于一个普通的方法

示例

public class ThreadTest {
    public static void main(String[] args) {
        OneThread o1 = new OneThread();
        o1.start();
        for(int i = 0; i< 1000000; i++){
            System.out.println(Thread.currentThread().getName());
        }
    }
}

class OneThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000000; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
}

//输出结果(节选)
Thread-0
Thread-0
Thread-0
main
main
main
main

更改之后

public class ThreadTest {
    public static void main(String[] args) {
        OneThread o1 = new OneThread();
        o1.start();
        for(int i = 0; i< 1000000; i++){
            System.out.println(Thread.currentThread().getName());
        }
    }
}

class OneThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000000; i++) {
            System.out.println(Thread.currentThread().getName());
        }
    }
}
//输出结果(节选)
main
main
main
//此时,全是main方法中的线程,相当于调用了一个普通类的普通方法,并不是多线程
问题二

能否在提供一个线程,用于输出偶数?

class PrintNumber{
    public void run(){
        for(int i = 0; i< 100 ;i++){
            if(i % 2 == 0){
                System.out.println(i);
            }
        }
    }
}

public class NumberTest{
    public static void main(String []args){
        PrintNumber p1 = new PrintNumber();
        p1.start();
        p1.start();
    }
}
//输出结果
0 - 100的 偶数(省略)
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.base/java.lang.Thread.start(Thread.java:1525)
	at 多线程.EvenNUmberTest.main(EvenNUmberTest.java:9)

不能让已经start()的线程再次执行star()方法,否则报异常。非法的线程状态。

若想要再次提供一个线程,可以再实例化一个对象,用这个对象调用start()方法

问题三

创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数

public class NumberTest {
   public static void main(String[] args) {
       EvenNumberPrint t1 = new EvenNumberPrint();
       OddNumberPrint t2 = new OddNumberPrint();
       t1.start();
       t2.start();
   }
}

class EvenNumberPrint extends Thread{   //用于打印偶数
   @Override
   public void run() {
       for (int i = 0; i <= 100; i++) {
           if(i % 2 == 0){
               System.out.println(Thread.currentThread().getName()+" "+i);
           }
       }
   }
}
class OddNumberPrint extends Thread{    //用于打印奇数
   @Override
   public void run() {
       for (int i = 0; i <= 100; i++) {
           if(i % 2 != 0){
               System.out.println(Thread.currentThread().getName()+" "+ i);
           }
       }
   }
}

实现方式之一 :实现Runnable接口

实现步骤

以下为实现Runnable接口的具体步骤

  • 创建一个实现Runnable接口的类
  • 实现接口中的run()方法 ——> 将此线程要执行的操作,声明在run()方法体中
  • 创建当前实现类的对象
  • 将此对象作为参数传递到Thread类中的构造器中,创建Thread类的实例
  • Thread类的实例调用start()方法。start的作用 ①启动线程②调用run()方法

普通方式

public class EvenNumberTest {
    public static void main(String[] args) {
        //创建当前类的实例化
        EvenNumberPrint p = new EvenNumberPrint();
        //将此对象作为参数传递到Thread类的构造器中
        Thread t1 = new Thread(p);
        t1.start();
    }
}

class EvenNumberPrint implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() +" "+ i);
        }
    }
}

//输出结果
//
Thread-0 0
Thread-0 1
    .....省略
Thread-0 100
    

使用接口匿名实现类的匿名对象

//使用实现Runnable接口的方式,提供了Runnable接口匿名实现类的匿名对象
public class EvenNumberTest {
    public static void main(String[] args) {
        new Thread(new Runnable(){
            public void run(){
                for(int i = 0; i < 100 ; i++){
                    System.out.println(Thread.currentThread().getName() + i);
                }
            }
        }).start();
    }
}

两种实现方式的对比

共同点

  • 启动线程时,使用的都是Thread类中定义的start()
  • 创建的线程对象,都是Thread类或其子类的实例

不同点

一个是类的继承,一个是接口的实现

建议

建议使用实现Runnable接口的实现。

  • 可以避免类的单继承的局限性
  • 更适合处理有共享数据的问题
  • 实现了代码和数据的分离

两种方式的联系

查看Thread的源码会发现,Thread类 也是实现了Ruunable接口

public class Thread implements Runnable {    }

标签:main,Java,Thread,创建,start,线程,run,多线程,public
From: https://blog.csdn.net/qq_35899077/article/details/139375350

相关文章

  • java 中byte的取值范围
    众所周知,java中byte的取值范围-128~127,那么为什么呢?java中二进制是采用补码运算的,其中最高位0代表正数1代表负数。正数的正码,反码,补码相同,负数补码=反码+1。举例:-10正码:10001010反码:11110101补码:11110110一字节byte占8bit位。那么正数范围为00000000~0111111......
  • 从零手写实现 nginx-01-为什么不能有 java 版本的 nginx?
    前言大家好,我是老马。很高兴遇到你。作为一个java开发者,工作中一直在使用nginx。却发现一直停留在使用层面,无法深入理解。有一天我在想,为什么不能有一个java版本的nginx呢?一者是理解nginx的设计灵魂,再者java开发者用java语言的服务器不是更加自然吗。于是动手开......
  • Java的冷知识你知道吗?
    1、方法参数不能超过255个在Java中,方法的参数数量是有限制的,最多不能超过255个。这个知识点可能对于大多数程序员来说并不常用,因此即使是经验丰富的Java开发者也可能不清楚这一点。2、Java中的自动装箱与拆箱自动装箱是Java5引入的新特性,它允许将基本数据类型自动转换成对应......
  • Java (IOC/IO Spring项目)
    前沿Maven解决问题项目中的iar包资源需要我们自己从网上下载后,手动导入到项目中使用,不好管理。jar包版本控制麻烦Maven是一个强大的项目管理和构建工具,主要用于Java项目。它提供了一种统一的构建系统,并且能够管理项目的依赖关系、构建过程、版本控制等。Maven采用了一......
  • Java中常见错误-Java中注解是否可以继承
    Java中注解是否可以继承@Inherited基本概念使用场景注意事项实体类自定义注解测试方法运行结果使用@Inherited不使用@Inherited结论在解决这个问题之前需要先了解一下@Inherited@Inherited基本概念​@Inherited是Java中的一个元注解,位于java.lang.annotatio......
  • C#.NET根据不同业务类别类型写入不同文件中,动态创建log4net实例验证
    C#.NET根据不同业务类别类型写入不同文件中,动态创建log4net实例验证 参考了:https://www.cnblogs.com/-dawn/p/8598566.html GetLog4netInstance:usinglog4net;usinglog4net.Appender;usinglog4net.Config;usinglog4net.Core;usinglog4net.Filter;usinglog4net.L......
  • javaScript基础22
    一、概念一门客户端脚本语言运行在客户端浏览器中的。每一个浏览器都有JavaScript的解析引擎脚本语言:不需要编译,直接就可以被浏览器解析执行了二、功能可以来增强用户和html页面的交互过程,可以来控制html元素,让页面有一些动态的效果,增强用户的体验。三、JavaScript发......
  • Java多线程
    线程的定义Java线程是Java编程语言中的执行单元。在Java中,线程可以看作是轻量级的进程,它独立运行,具有自己的执行路径。线程的原理Java线程的实现基于操作系统的线程模型,但Java虚拟机(JVM)对线程的管理和调度做了封装和优化,使得Java线程更加可控和可靠。下面是Java线程的一些基本......
  • 2.3Docker部署java工程
    2.3Docker部署java工程1.导入jar包2.在Docker部署jdk(容器名为myjdk17)3.修改jar包名mv原包名新包名4.配置启动脚本Dockerfile是一个文本文件,其中包含了构建Docker镜像所需的一系列步骤和指令。通过编写Dockerfile文件,可以生成我们想要的镜像。基于JDK17镜像使......
  • Java18新特性有哪些
    Java18于2022年3月22日正式发布,它带来了一些新特性和改进,主要包括以下几点:JEP400:UTF-8byDefault123:JDK将UTF-8设置为默认字符集,这使得依赖于默认字符集的API在所有实现、操作系统、区域设置和配置中保持一致。JEP408:SimpleWebServer123:引入了一个简......