【Java多线程】多线程的三种实现方式和多线程常用方法

您所在的位置:网站首页 java多线程应用在哪些方面中使用 【Java多线程】多线程的三种实现方式和多线程常用方法

【Java多线程】多线程的三种实现方式和多线程常用方法

2024-07-06 10:15| 来源: 网络整理| 查看: 265

目录

1、多线程的三种实现方式

1.1、继承Thread类的方式进行实现

1.2、实现Runnable接口的方式进行实现

1.3、利用Callable接口和Future接口方式实现

1.4、三种实现方式的优缺点

2、多线程常用方法

1、多线程的三种实现方式

        在main()方法中,你可以创建和启动额外的线程,这些线程称为子线程。子线程可以并行执行,与主线程同时进行。多线程的三种实现方式如下:

继承Thread类的方式进行实现实现Runnable接口的方式进行实现利用Callable接口和Future接口方式实现 1.1、继承Thread类的方式进行实现

        java.lang.Thread是Java提供的线程类,继承了该类的就是一个线程类,所有的线程对象都必须是 Thread 类或其⼦类的实例。每个线程的作⽤是完成⼀定的任务,实际上就是执⾏⼀段程序流即⼀段顺序执⾏的代码,Java 使⽤线程执⾏体来代表这段程序流。主线程和分支线程是并发执行的,谁在前谁在后是随机的抢占式分配。Java中通过继承Thread类来创建并启动多线程的步骤如下:

        1. 定义 Thread 类的⼦类,并重写该类的 run() ⽅法,该 run() ⽅法的⽅法体就代表了线程需要完成的任务,因此把 run() ⽅法称为线程执⾏体。

        2. 创建 Thread ⼦类的实例,即创建了线程对象

        3. 调⽤线程对象的 start() ⽅法来启动该线程

定义线程,getName()方法可以在线程启动时获取线程的名字

public class MyThread extends Thread{ @Override public void run() { //书写线程要执行代码 for (int i = 0; i < 15; i++) { System.out.println(getName() + " Holle world"); } } }

创建线程对象,并启动线程,t1.setName("线程1"); t2.setName("线程2");可以给线程对象命名

public class ThreadDemo { public static void main(String[] args) { /*多线程的第一种启动方式: 1.自己定义一个类继承Thread 2.重写run方法 3.创建子类的对象,并启动线程 */ MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.setName("线程1"); t2.setName("线程2"); t1.start(); t2.start(); } }

运行结果

1.2、实现Runnable接口的方式进行实现

        采⽤ java.lang.Runnable 实现也是⾮常常⻅的⼀种,只需要重写 run ⽅法即可。

        步骤如下:

        1. 定义 Runnable 接⼝的实现类,并重写该接⼝的 run() ⽅法,该 run() ⽅法的⽅法体同样是该线程的线程执⾏体。

        2. 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是 真正的线程对象。

        3. 调⽤线程对象的 start() ⽅法来启动线程。

定义任务类,要实现Runnable接口,实现接口中的 run()方法

public class MyRun implements Runnable { @Override public void run() { //书写线程要执行代码 for (int i = 0; i < 15; i++) { //currentThread()方法获取到当前线程的对象 /*Thread t = Thread.currentThread(); System.out.println(t.getName()+"HelloWorld!"); */ //把上面的两行代码改成链式编程的写法 System.out.println(Thread.currentThread().getName() + " Holle world"); } } }

创建任务的对象,创建线程对象,并且把任务传递给线程对象,然后开启线程

public class ThreadDemo { public static void main(String[] args) { /*多线程的第二种启动方式:1.自己定义一个类实现Runnable接口 2.重写里面的run方法 3.创建自己的类的对象 4.创建一个Thread类的对象,并开启线程 */ //创建MyRun的对象 // 表示多线程要执行的任务 MyRun mr = new MyRun(); //创建线程对象,并且把任务传递给线程对象 Thread t1 = new Thread(mr); Thread t2 = new Thread(mr); //给线程设置名字 t1.setName("线程1"); t2.setName("线程2"); //开启线程 t1.start(); t2.start(); } }

运行结果

1.3、利用Callable接口和Future接口方式实现

        Callable接口是Runable接口的增强版。同样用call()方法作为线程的执行体,增强了之前的run()方法。因为call方法可以有返回值,也可以声明抛出异常。

        Future接口用来代表Callable接口里的call()方法的返回值,FutureTask类是Future接口的一个实现类,FutureTask类实现了RunnableFuture接口,而RunnnableFuture接口继承了Runnable和Future接口,所以说FutureTask是一个提供异步计算的结果的任务。

        

        步骤如下:

                1.创建一个类MyCallable实现Callable接口                 2.重写call (是有返回值的,表示多线程运行的结果)                 3.创建MyCallable的对象(表示多线程要执行的任务)                 4.创建FutureTask的对象(作用管理多线程运行的结果)                 5.创建Thread类的对象,并启动(表示线程)

定义任务类,要实现Callable接口,实现接口中的 call() 方法

public class MyCallable implements Callable { @Override public Integer call() throws Exception { int result = 0; System.out.println(Thread.currentThread().getName() + " Holle world"); for (int i = 0; i < 15; i++) { result += i; } return result; } }

创建FutureTask的对象,创建Thread类的对象,并启动

public class ThreadDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { /*多线程的第三种实现方式: 特点:可以获取到多线程运行的结果 */ //创建MyCallable的对象(表示多线程要执行的任务) MyCallable mc = new MyCallable(); //创建FutureTask的对象(作用管理多线程运行的结果) FutureTask fu = new FutureTask(mc); FutureTask fu1 = new FutureTask(mc); //创建线程的对象 Thread t1 = new Thread(fu); Thread t2 = new Thread(fu1); t1.setName("线程1"); t2.setName("线程2"); //启动线程 t1.start(); t2.start(); //获取多线程运行的结果 Integer result1 = fu.get(); Integer result2 = fu1.get(); System.out.println(result1 + " : " + result2); } } 1.4、三种实现方式的优缺点

方式

优点

缺点

继承Thread类

编程比较简单,可以直接使用Thread类中的方法

可以扩展性较差,不能再继承其他的类

实现Runnable接口

扩展性强,实现该接口的同时还可以继承其他的类

编程相对复杂,不能直接使用Thread类中的方法

实现ca1lable接口

2、多线程常用方法

方法名称

说明

String getName()

返回此线程的名称

int getId()

返回此线程的ID

void setName(String name)

设置线程的名字(构造方法也可以设置名字)

static Thread currentThread( )

获取当前线程的对象

static void sleep(long time)

让线程休眠指定的时间,单位为毫秒

setPriority(int newPriority)

设置线程的优先级

final int getPriority( )

获取线程的优先级

final void setDaemon(boolean on)

设置为守护线程

public static void yield( )

出让线程/礼让线程

public static void join( )

插入线程/插队线程

常用方法注意点:

String getName() 返回此线程的名称

void setName(string name) 设置线程的名字(构造方法也可以设置名字)

1、如果我们没有给线程设置名字,线程也是有默认的名字的,格式是Thread-X(X序号,从0开始的)

2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置

static Thread currentThread() 获取当前线程的对象

当IVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程,他的作用就是去调用main方法,并执行里面的代码,在以前,我们写的所有的代码,其实都是运行在main线程当中

static void sleep(long time) 让线程休眠指定的时间,单位为毫秒

1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间

2、方法的参数:就表示睡眠的时间,单位毫秒,1 秒=1000毫秒

3、当时间到了之后,线程会自动的醒来,抢占到CUP后,继续执行下面的其他代码

注意:Java中的线程调度采用的是抢占式的,线程的优先级从1到10,线程的优先级越低抢占CUP的概率就越低,线程的优先级越高抢占CUP的概率就越高,不是说线程的优先级越高就一定能抢占到CUP的,这是一个概率问题,并不是绝对的

自定义线程两个线程

//自定义线程MyThread1 public class MyThread1 extends Thread{ @Override public void run() { //书写线程要执行代码 for (int i = 0; i < 15; i++) { System.out.println(getName() +"@"+ i); } } } //自定义线程MyThread2 public class MyThread2 extends Thread { @Override public void run() { //书写线程要执行代码 for (int i = 0; i < 70; i++) { System.out.println(getName() +"@"+ i); } } }

final void setDaemon(boolean on)方法演示

守护线程的应用场景,假设有两个人通过QQ在聊天,并且有文件在传输,这时候就会有两个线程,分别是:聊天(线程1)和传输文件(线程2),当聊天结束,即线程1被关闭了,传输文件自然也就要关闭了,所以线程2要被设置成守护线程

public class ThreadDemo1 { public static void main(String[] args) { /* * final void setDaemon(boolean on) 设置为守护线程 * 提示:当其他的非守护线程执行完毕之后,守护线程会陆续结束 * 通俗易懂:当女神线程结束了,那么备胎线程也没有存在的必要了 */ MyThread1 t1 = new MyThread1(); MyThread2 t2 = new MyThread2(); t1.setName("主线程"); t2.setName("守护线程"); //把第二个线程设置为守护线程(备胎线程) t2.setDaemon(true); //启动线程 t1.start(); t2.start(); } }

从运行结果可看出,主线程执行完毕之后,守护线程就陆续结束了

java中线程的执行过程

        Java中的主线程是程序的入口点,通常是在main()方法中定义。当程序启动时,主线程会从main()方法开始执行。当主线程遇到创建和启动子线程的代码时,它会创建一个新的线程对象,并调用该线程对象的start()方法,以启动新的线程。子线程在自己的run()方法中定义要执行的任务。

        主线程和子线程之间的执行顺序取决于调度器的策略。调度器负责分配CPU时间给每个线程,以便它们能够交替执行。

        通常情况下,主线程会先执行main()方法中的代码,然后创建和启动子线程。子线程的执行顺序可能是不确定的,取决于操作系统和Java虚拟机的实现。主线程和子线程可以同时执行,互不干扰。

        需要注意的是,如果主线程在子线程之前结束,那么子线程可能无法执行完毕。为了确保子线程能够完成任务,可以使用join()方法,在主线程中调用该方法等待子线程执行完毕。

推荐:

【Java多线程】多线程的三种实现方式和多线程常用方法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136961604【Java多线程】多线程的三种实现方式和多线程常用方法-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136961604【java基础】异常处理机制-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/m0_65277261/article/details/136581375?spm=1001.2014.3001.5501



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3