Java--多线程--Thread类+Runnable接口

news2024/11/8 7:41:14

1.多进程与多线程

1.1多进程:

        一个进程是一个包含自身地址的程序,每个独立执行的程序都称为进程,也就是正在执行的程序,系统可以分配给每个进程一段有限的使用CPU的时间(CPU时间片),CPU在这个时间段中执行某个进程,然后下一个时间片又会跳至另一个进程中去执行;由于CPU转换很快,所以使得每个进程好像是在同时执行一样。

1.2多线程:

        Java语言提供了并发机制,程序中可以执行多个线程,每个线程完成一个功能,并于其他线程并发执行,这种机制被称为多线程。

        一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程可以得到一下段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。

2.实现线程的2种方式

2.1 继承Thread类

        继承java.lang.Thread类,从这个类中实例化的对象代表线程,启动一个新线程需要建立一个Thread实例。构造方法:

2.1.1 public Thread()

        创建一个新的线程对象。

2.1.2 public Thread(String threadName)

        创建一个名为threadName的线程对象。

public class ThreadTest extends Thread{

        //

}

2.1.3 run()方法:

        完成线程真正功能的代码凡在类的run()方法中,当一个类继承Thread类后,就可以重写覆盖run()方法;

        run()方法必须使用一下语法:

public void run(){

        //

}

2.1.4 start()方法:

        调用Thread类中的strat()方法启动执行线程,start()方法会调用run()方法。

 public static void main(String[] args){

        new ThreadTest().start();

}

主方法main()线程的启动是由Java虚拟机负责的,我们只需要负责自动自己定义的线程即可。

package threadwork;

public class CountThread extends Thread {        //指定继承Thread类
    private int count = 10;

    public void run() {          //重写run()方法
        while (true) {
            System.out.print(count + " ");
            if (--count == 0) {     //count自减
                return;
            }
        }
    }

    public static void main(String[] args) {
        CountThread ct = new CountThread();     //实例化线程对象
        ct.start();         //启动线程
    }
}

输出:
        10 9 8 7 6 5 4 3 2 1 

2.2 实现Runable接口

        Thread 是类,而Runnable是接口;Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性;如果我们定义的类相想要继承其他类(非Thread类),并且还要当前定义的类实现多线程,可以通过Runnable接口来实现。

        此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。

        实际上,Thread类就是实现了Runnable接口,Thread类中的run()方法也是对Runnable接口中的run()方法的实现。

2.2.1 语法:

public class MyDemo extends Object implents Runable{

        //

2.2.2 继承Thread类实现多线程

package threadwork;

class Ticket extends Thread {
    public void run() {
        for (int ticket = 10; ticket > 0; ticket--) {
            System.out.println(this.getName() + " 买票:ticket" + ticket);
        }
    }
}

public class TicketThreadTest {
    public static void main(String[] args) {
        Ticket tt_1 = new Ticket();
        Ticket tt_2 = new Ticket();
        Ticket tt_3 = new Ticket();
        tt_1.start();
        tt_2.start();
        tt_3.start();
    }
}

输出:
        Thread-0 买票:ticket10
        Thread-2 买票:ticket10
        Thread-1 买票:ticket10
        Thread-2 买票:ticket9
        Thread-2 买票:ticket8
        Thread-2 买票:ticket7
        Thread-2 买票:ticket6
        Thread-0 买票:ticket9
        Thread-0 买票:ticket8
        Thread-2 买票:ticket5
        Thread-2 买票:ticket4
        Thread-1 买票:ticket9
        Thread-2 买票:ticket3
        Thread-0 买票:ticket7
        Thread-2 买票:ticket2
        Thread-1 买票:ticket8
        Thread-1 买票:ticket7
        Thread-1 买票:ticket6
        Thread-2 买票:ticket1
        Thread-0 买票:ticket6
        Thread-0 买票:ticket5
        Thread-1 买票:ticket5
        Thread-1 买票:ticket4
        Thread-0 买票:ticket4
        Thread-0 买票:ticket3
        Thread-1 买票:ticket3
        Thread-0 买票:ticket2
        Thread-1 买票:ticket2
        Thread-1 买票:ticket1
        Thread-0 买票:ticket1

2.2.3 实现Runnale接口的多线程

使用Runnable接口启动新的线程步骤如下:

        a.定义的类实现Runnable接口;

        b.定义的类中实现run()方法;

        c.实例化建立Runnable对象(自定义类的对象);

        d.使用参数为Runnable对象的构造方法创建Thread实例;

        e.调用start()方法启动线程;

package threadwork;

class TicketR implements Runnable {
    public void run() {
        for (int ticket = 0; ticket <= 10; ticket++) {
            System.out.println(Thread.currentThread().getName() + " 买票:ticket" + ticket);
        }
    }
}

public class TicketRunable {
    public static void main(String[] args) {
        TicketR ticket_R = new TicketR();
        Thread t1 = new Thread(ticket_R);
        Thread t2 = new Thread(ticket_R);
        Thread t3 = new Thread(ticket_R);
        t1.start();
        t2.start();
        t3.start();
    }
}

输出:
        Thread-1 买票:ticket0
        Thread-1 买票:ticket1
        Thread-1 买票:ticket2
        Thread-1 买票:ticket3
        Thread-1 买票:ticket4
        Thread-1 买票:ticket5
        Thread-1 买票:ticket6
        Thread-1 买票:ticket7
        Thread-0 买票:ticket0
        Thread-0 买票:ticket1
        Thread-0 买票:ticket2
        Thread-2 买票:ticket0
        Thread-0 买票:ticket3
        Thread-0 买票:ticket4
        Thread-0 买票:ticket5
        Thread-1 买票:ticket8
        Thread-1 买票:ticket9
        Thread-1 买票:ticket10
        Thread-0 买票:ticket6
        Thread-2 买票:ticket1
        Thread-2 买票:ticket2
        Thread-2 买票:ticket3
        Thread-2 买票:ticket4
        Thread-2 买票:ticket5
        Thread-0 买票:ticket7
        Thread-2 买票:ticket6
        Thread-2 买票:ticket7
        Thread-2 买票:ticket8
        Thread-2 买票:ticket9
        Thread-2 买票:ticket10
        Thread-0 买票:ticket8
        Thread-0 买票:ticket9
        Thread-0 买票:ticket10

3.线程的生命周期

        虽然多线程看起来像同时执行,但事实上单个CPU在同一时间点上只有一个线程在被执行,只是线程之间切换较快,才有同时执行的假象。

3.1 线程具有7种声明周期:

        1.出生状态、2.就绪状态、3.运行状态、4.等待状态、5.休眠状态、6.阻塞状态、7.死亡状态。

当线程的run()方法执行完毕时,线程会进入死亡状态。

3.2 使线程处于就绪状态的方法:

        3.2.1调用sleep()方法:

        当线程调用Thread类中的sleep()方法时,则会进入休眠状态;

        3.2.2 调用wait()方法:

        当处于运行状态下的线程调用Thread类中的wait()方法时,该线程就会进入等待状态。

        3.2.3 等待输入/输出完成;

        当运行中线程在运行状态下发出I/O请求,该线程会进入阻塞状态,I/O结束时线程会进入就绪状态,对于阻塞的线程来说,既是系统资源空闲,线程依然不能回到运行状态。

3.3 使线程从就绪状态-->运行状态的方法:

        3.3.1 线程调用notify()方法:

        进入等待状态的线程必须调用Thread类中的notify()方法才能被唤醒;

        3.3.2 线程调用notifyAll()方法:

        将所有处于等待状态下的线程唤醒;

        3.3.3 线程调用interrupt()方法:

        3.3.4 线程的休眠时间结束;

        3.3.5 输入/输出结束;

4.操作线程的方法

4.1 线程的休眠:sleep()方法

        sleep()方法参数为毫秒为单位的时间,同时在run()方法中循环被使用。

try{

        Thread.sleep(2000);        //线程休眠等待2秒

}catch(InterruptException e){

        e.printStackTrace();

}

上述代码使线程在2S之内不会进入就绪状态;虽然使用了sleep()方法的线程在一段时间内会醒来,但是并不能保证醒来后它就会进入运行状态,只能保证它进入就绪状态。 

4.2 线程的加入:join()方法

        当一个线程使用join()方法加入另外一个线程时,另外一个线程会等待这个加入的线程执行完毕后再继续执行;

        通常用于在main()主线程内,等待其它子线程完成再接着执行main()主线程;

4.3 线程的中断:布尔型标记控制

        以前会使用stop()方法来停止线程,但是JDK不推荐使用此方法,提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。

public class InterruptedTest implements Runnable{

        private boolean isContine = false;        //设置一个标记变量,默认设置为false

        public void run(){                                        //重写run()方法

                while(true){

                        //dosomething

                        if (isContinue){                        //当isContinue变为true时,停止线程

                                break;

                                                }

                                }

                        }

        

        public void setContinue(){

                this.isContinue = true;                //定义设置变量isContinue的方法

        }

}

4.4 线程的礼让:yield()方法

        Thread类中提供了礼让方法yield(),给当前正在运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅仅是提醒,没有任何机制保证当前线程会礼让资源;

5.线程的优先级

        每个线程都具有各自的优先级,操作系统会根据线程的优先级来决定首先使哪个线程进入运行状态。

5.1 Thread类中成员变量代表了常用优先级:

        5.1.1 Thread.MIN_PRIORITY(常数1)

        5.1.2 Thread.MAX_PRIORITY(常数10)

        5.1.3 Thread.NORM_PRIORITY(常数5)

在默认情况下,优先级都是Thread.NORM_PRIORITY,且每个新产生的线程都会继承父线程的优先级。

5.2 调整线程优先级:setPriority()方法

setPriority()方法的参数为1~10的数值,数值越大,代表优先级越高;

先设置优先级,再start()启动;

package threadwork;

class TicketR implements Runnable {
    public void run() {
        for (int ticket = 0; ticket <= 2; ticket++) {
            System.out.println(Thread.currentThread().getName() + " 买票:ticket" + ticket);
        }
    }
}

public class TicketRunable {
    public static void main(String[] args) throws InterruptedException {
        TicketR ticket_R = new TicketR();
        Thread t0 = new Thread(ticket_R);
        Thread t1 = new Thread(ticket_R);
        Thread t2 = new Thread(ticket_R);
        t0.setPriority(1);     //先设置优先级,再start()启动
        t0.start();
        t0.join();      //主线程等待t1线程执行完毕

        t1.setPriority(4);
        t1.start();
        t1.join();      //主线程等待t2线程执行完毕

        t2.setPriority(10);
        t2.start();
        t2.join();      //主线程等待t3线程执行完毕
        System.out.println("主线程执行结束");
    }
}

6.线程的同步

        Java提供线程同步机制来防止资源访问的冲突。

6.1 线程安全

 问题示例:

package threadwork;

import com.sun.xml.internal.ws.api.ha.StickyFeature;

public class ThreadSafeTest implements Runnable {
    private int tikets = 10;

    @Override
    public void run() {
        while (true) {
            if (tikets > 0) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                tikets--;
                System.out.println(Thread.currentThread().getName() + " 抢票后剩余票:" + tikets + " 张");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadSafeTest tst = new ThreadSafeTest();
        Thread t0 = new Thread(tst);
        Thread t1 = new Thread(tst);
        Thread t2 = new Thread(tst);
        t0.start();
        t1.start();
        t2.start();
    }
}

输出:
        Thread-2 抢票后剩余票:8 张
        Thread-0 抢票后剩余票:8 张
        Thread-1 抢票后剩余票:8 张
        Thread-1 抢票后剩余票:6 张
        Thread-0 抢票后剩余票:6 张
        Thread-2 抢票后剩余票:5 张
        Thread-1 抢票后剩余票:2 张
        Thread-0 抢票后剩余票:2 张
        Thread-2 抢票后剩余票:2 张
        Thread-1 抢票后剩余票:1 张
        Thread-0 抢票后剩余票:0 张
        Thread-2 抢票后剩余票:-1 张
        Thread-1 抢票后剩余票:-2 张

6.2 线程同步机制:synchronized关键字

       给共享资源上一道锁, 给定时间只允许一个线程访问共享资源。

        6.2.1 同步块

        语法:

synchronized(Object){

        //

}        

        通常将共享资源的操作放在synchronized定义的区域内,这样当其他线程也想获取到这个锁时,必须等到锁被释放时才能进入到这个区域。 

package threadwork;

public class ThreadSafeTest implements Runnable {
    private int tikets = 10;

    @Override
    public void run() {
        while (true) {
            synchronized ("") {
                if (tikets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    tikets--;
                    System.out.println(Thread.currentThread().getName() + " 抢票后剩余票:" + tikets + " 张");
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadSafeTest tst = new ThreadSafeTest();
        Thread t0 = new Thread(tst);
        Thread t1 = new Thread(tst);
        Thread t2 = new Thread(tst);
        t0.start();
        t1.start();
        t2.start();
    }
}

输出:
        Thread-0 抢票后剩余票:9 张
        Thread-0 抢票后剩余票:8 张
        Thread-0 抢票后剩余票:7 张
        Thread-0 抢票后剩余票:6 张
        Thread-0 抢票后剩余票:5 张
        Thread-0 抢票后剩余票:4 张
        Thread-0 抢票后剩余票:3 张
        Thread-0 抢票后剩余票:2 张
        Thread-0 抢票后剩余票:1 张
        Thread-0 抢票后剩余票:0 张

        6.2.2 同步方法

        语法:

synchronized void funName(){

        //

}

package threadwork;

public class ThreadSafeTest implements Runnable {
    private int tikets = 10;

    @Override
    public synchronized void run() {
        while (true) {
            if (tikets > 0) {
                try {
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                tikets--;
                System.out.println(Thread.currentThread().getName() + " 抢票后剩余票:" + tikets + " 张");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadSafeTest tst = new ThreadSafeTest();
        Thread t0 = new Thread(tst);
        Thread t1 = new Thread(tst);
        Thread t2 = new Thread(tst);
        t0.start();
        t1.start();
        t2.start();
    }
}

输出:
        Thread-0 抢票后剩余票:9 张
        Thread-0 抢票后剩余票:8 张
        Thread-0 抢票后剩余票:7 张
        Thread-0 抢票后剩余票:6 张
        Thread-0 抢票后剩余票:5 张
        Thread-0 抢票后剩余票:4 张
        Thread-0 抢票后剩余票:3 张
        Thread-0 抢票后剩余票:2 张
        Thread-0 抢票后剩余票:1 张
        Thread-0 抢票后剩余票:0 张

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1164783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库实验:SQL的多表数据查询

目录 实验目的实验内容实验要求实验过程实验代码结果示意 书接上文&#xff0c;但是感觉之前的形式不太好用&#xff0c;至少不是很方便观看&#xff0c;所以这篇尝试改变一下写法&#xff0c;希望可以提升一些观感 实验目的 (1) 掌握RDBMS的数据多表查询功能 (2) 掌握SQL语言…

Junit使用

一、Junit常用注释 Test 将一个普通的方法修饰成为一个测试方法。 Test&#xff08;exceptedXX.class&#xff09; Test(exceptedArithmeticException.class):预期被测方法是否抛出ArithmeticException异常Test&#xff08;timeout毫秒&#xff09;BeforeClass&#xff1a;它…

velero备份k8s集群

流程图 velero备份原理 本地 Velero 客户端发送备份指令。Kubernetes 集群内就会创建一个 Backup 对象。BackupController 监测 Backup 对象并开始备份过程。BackupController 会向 API Server 查询相关数据。BackupController 将查询到的数据备份到远端的对象存储。 velero的…

【深度学习】pytorch——Tensor(张量)详解

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ pytorch——Tensor 简介创建Tensortorch.Tensor( )和torch.tensor( )的区别torch.Tensor( )torch.tensor( ) tensor可以是一个数&#xff08;标量&#xff09;、一维数组&#xff08;向量&#xff09;、二维数组&…

EasyExcel动态复杂表头导出方法

目录 需求分析解决方案数据问题数据导入 需求分析 公司数据比较特殊有一部分数据需要动态修改导致信息导入时表头是不确定的&#xff0c;但其中又有一部分表头是固定的&#xff0c;如下图所示&#xff0c;如果表头全部是固定的话可以通过EasyExcel实体类的注解很轻松的解决&am…

Linux CentOS7.9安装OpenJDK17

Linux CentOS7.9安装OpenJDK17 一、OpenJDK下载 清华大学开源软件镜像站 国内的站点&#xff0c;下载速度贼快 二、上传解压 文件上传到服务器后&#xff0c;解压命令&#xff1a; tar -zxvf jdk-xxxx-linux-x64.tar.gz三、配置环境 export JAVA_HOME/home/local/java/j…

ffmpeg mp3截取命令,视频与mp3合成带音频视频命令

从00:00:03.500开始截取往后长度到结尾的mp3音频&#xff08;这个更有用&#xff0c;测试好用&#xff09; ffmpeg -i d:/c.mp3 -ss 00:00:03.500 d:/output.mp3 将两个音频合并成一个音频&#xff08;测试好用&#xff09; ffmpeg -i "concat:d:/c.mp3|d:/output.mp3&…

Linux C语言进阶-D10指针数组

指针变量构成的数组 理解下面printf中的a和p的表示&#xff0c;其中p[0]、p[1]、p[2]表示存储的a,a1和a2这几个地址&#xff0c;而再加个*&#xff0c;相当于对地址解引用&#xff0c;从而得到数组中的值。 如下图&#xff0c;要想得到a[0][1]的值可以直接打印a[0][1]&#xf…

使用pytorch处理自己的数据集

目录 1 返回本地文件中的数据集 2 根据当前已有的数据集创建每一个样本数据对应的标签 3 tensorboard的使用 4 transforms处理数据 tranfroms.Totensor的使用 transforms.Normalize的使用 transforms.Resize的使用 transforms.Compose使用 5 dataset_transforms使用 1 返回本地…

YOLOv5:修改backbone为SPPCSPC

YOLOv5&#xff1a;修改backbone为SPPCSPC 前言前提条件相关介绍SPPCSPCYOLOv5修改backbone为SPPCSPC修改common.py修改yolo.py修改yolov5.yaml配置 参考 前言 记录在YOLOv5修改backbone操作&#xff0c;方便自己查阅。由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬…

一文读懂最小相位滤波器和线性相位滤波器

一文读懂最小相位滤波器和线性相位滤波器 1. 举例说明2. 最小相位定义2.1 最小相位多项式2.2 最大相位滤波器2.3 最小相位意味最快的衰减2.4 最小相位/全通分解 3. 建立最小相位系统 前一篇博客 《一文读懂滤波器的线性相位&#xff0c;全通滤波器&#xff0c;群延迟》 详细解…

curl(二)HTTP协议和头

一 HTTP协议相关 ① 强制发出请求的http1.0 7.29 版本默认是http1.1 ② 查看当前curl版本是否支持http2 方式2: curl --version看Features 补充&#xff1a; 7.33.0 版本才引入 http2,才能使用curl发出http2.0版本的请求 ③ 强制发送http3 说明&#xff1a; 了解即可 二…

DevChat:超越编码的未来 - 优势、安装、使用、以及未来前景

目录 前言1 DevChat的优势1.1 精确的上下文控制1.2 灵活的提示管理1.3 上下文构建1.4 提前准备好的提示模板1.5 高级命令控制 2 安装DevChat插件3 使用DevChat插件3.1 代码生成3.2 文档撰写3.3 解释代码3.4 解决问题3.5 版本控制 4 DevChat的未来前景结语 前言 在软件开发领域…

Docker 多阶段构建的原理及构建过程展示

Docker多阶段构建是一个优秀的技术&#xff0c;可以显著减少 Docker 镜像的大小&#xff0c;从而加快镜像的构建速度&#xff0c;并减少镜像的传输时间和存储空间。本文将详细介绍 Docker 多阶段构建的原理、用途以及示例。 Docker 多阶段构建的原理 在传统的 Docker 镜像构建…

阿里面试:让代码不腐烂,DDD是怎么做的?

说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 谈谈你的高并发落地经验&#xff1f; 谈谈你对DDD的理解&#xf…

CIM与MES

CIM系统&#xff0c;全称计算机集成制造系统&#xff08;Computer-Integrated Manufacturing&#xff09;&#xff0c;是一种集成了计算机技术、网络通讯技术和软件系统的制造自动化框架。CIM的主要目标是整合制造过程中的所有活动&#xff0c;包括生产管理、设备管理和品质管理…

物流小程序制作教程:从零到有,详细解析

随着互联网的快速发展&#xff0c;物流行业也逐渐实现了数字化转型。为了满足消费者对更加便捷、高效的服务需求&#xff0c;许多物流企业选择制作自己的小程序。本文将通过乔拓云网后台&#xff0c;带你轻松搭建物流小程序&#xff0c;主要分为以下几个部分&#xff1a; 一、进…

设置echarts折线图虚线

itemStyle:{normal: {lineStyle: { type: solid}}}itemStyle:{normal: {lineStyle: { type: dashed}}}放到每个红框里面

梯度消失和梯度爆炸的原因

梯度消失和梯度爆炸 梯度爆炸和梯度消失本质上是因为梯度反向传播中的连乘效应。 梯度下降算法 举一个简单的例子,函数表达式为loss 2w^2 4w,如下图 ​​​​​​​ ​​​​​​​ 为了求得w的最优值,使得loss最小,从上图很容易看出来当w -1时,loss最小…

ER图设计神器,帮你省时省力,高效完成工作!

ER图&#xff08;Entity-Relationship Diagram&#xff09;工具用于设计数据库模型&#xff0c;通常用于表示数据实体、关系和属性之间的关系。以下是10个好用的ER图工具。 一、Lucidchart Lucidchart 是一款基于云的协作式图表设计工具&#xff0c;它允许用户创建、编辑和共享…