java多线程一

news2024/11/27 10:39:42

1、什么是线程

        线程(Thread)是一条程序内部的一条执行流程。

        程序中如果只有一条执行流程,那这个程序就是单线程的程序。

2、什么是多线程

        多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理“。

3、多线程的优缺点

3.1、优点

  • 同时执行多个任务,提高程序的工作效率。
  • 提高CPU的使用率。
  • 线程之间可以共享资源。
  • 相比进程而言,创建线程代价比较小。

 3.2、缺点

  • 等候使用共享资源时造成程序的运行速度变慢。这些共享资源主要是独占性的资源 ,如打印机等。
  • 对线程进行管理要求额外的 CPU开销,线程的使用会给系统带来上下文切换的额外负担
  • 可能会出现线程的死锁。即对共享资源加锁实现同步的过程中可能会死锁。

 4、java中的多线程

        在java语言中: 线程A和线程B,堆内存和方法区内存共享。 但是栈内存独立,一个线程一个栈。假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,互不干扰,各自执行各自的,这就是多线程并发。

5.、java多线程的声明周期

  • 创建(New):线程对象通过 new 关键字创建,但还未调用 start() 方法时,线程处于新建状态。此时,线程对象已经分配了内存空间,但尚未启动执行。
  • 就绪(Runnable):线程对象调用 start() 方法后,线程处于就绪状态。此时,线程已经准备好执行,但还没有获得 CPU 时间片。多个线程处于就绪状态时,由 Java 虚拟机的线程调度器来决定哪个线程获得 CPU 时间片开始执行。
  • 运行(Running):当线程获得 CPU 时间片开始执行时,线程处于运行状态。此时,线程的 run() 方法正在被执行。
  • 阻塞(Blocked):在特定情况下,线程可能会被暂时挂起,进入阻塞状态。例如,线程调用了 sleep() 方法、等待 I/O 操作、获得了某个对象的锁但没有获取到锁等。当阻塞状态的条件解除时,线程会重新进入就绪状态,等待获取 CPU 时间片继续执行。
  • 销毁(Terminated):线程执行完 run() 方法后,或者调用了 stop() 方法,线程将进入销毁状态。一旦线程进入了销毁状态,就无法再恢复到其他状态。

 6、Java中多线程的实现方式

6.1、继承Thread类

  1. 定义一个类继承Thread类,重写run方法
  2. 创建调用线程类的对象
  3. 调用线程对象的start方法启动线程(启动后会自动执行MyThread中重写的run()方法)
/**
 *  1、类继承Thread类
 **/
public class ThreadTest extends Thread{
    //必须重写Thread类中的run方法
    @Override
    public void run() {
        //super.run();
        for (int i = 0; i <= 5; i++) {
            System.out.println("子线程:"+i);
        }
    }
}

public class ThreadMain {
    public static void main(String[] args) {
        //2、创建子线程对象
        Thread t = new ThreadTest();
        //3、启动子线程
        t.start();

        for (int i = 0; i <= 5; i++) {
            System.out.println("主线程:"+i);
        }
    }
}

PS:

  1. 该方法编码简单,但使用了继承,不利于扩展。
  2. 启动线程必须是用start方法,不能用run方法,否知会变成单线程。
  3. 不要把主线程任务放到启动子线程之前,否则会变成成主线程执行完了,才执行子线程。

6.2、实现Runnable接口

  1. 定义一个线程任务类MyRunnable实现Runnable接口,重写run方法
  2. 创建MyRunnable对象
  3. 把MyRunnable对象交给Thread处理  
/**
 * 1、实现Runnable接口
 **/
public class RunnableTest implements Runnable{
    //重现run方法
    @Override
    public void run() {
        for (int i = 0; i <= 5; i++) {
            System.out.println("子线程:"+i);
        }
    }
}

public class RunnableMain {
    public static void main(String[] args) {
        /**
         * 2.创建子线程对象
         */
        Runnable target = new RunnableTest();

        /**
         * 3.把Runnable对象交给Thread处理
         */
        Thread t = new Thread(target);
        t.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("主线程执行输出" + i);
        }
    }
}

PS:实现接口,可以继续继承或者实现接口,扩展性强

 匿名内部类(推荐方法)

public class RunnableMain1 {
    public static void main(String[] args) {
        //简化方式一
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    System.out.println("子线程1:"+i);
                }
            }
        };
        new Thread(r).start();
        //简化方式二
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 5; i++) {
                    System.out.println("子线程2:"+i);
                }
            }
        }).start();

        //简化方式三(lambda表达式)(jdk8以上)
        new Thread(() -> {
                for (int i = 0; i <= 5; i++) {
                    System.out.println("子线程3:"+i);
                }
        }).start();

        for (int i = 0; i < 5; i++) {
            System.out.println("主线程执行输出" + i);
        }
    }
}

6.3、实现Callable接口,通过FutureTask接口接收返回值(JDK5新增)

  1. 得到任务对象 第一步:定义一个线程任务类MyCallable实现Callable接口,重写call方法,该方法可以返回结果 第二步:用Future吧Callable对象封装成线程任务对象
  2. 把线程任务对象交给Thread处理
  3. 调用Thread的start方法启动任务
  4. 线程执行完毕后,通过FutureTask的get方法获得结果 
/**
 *  1、定义一个实现类,实现Callable接口,记得声明结果的数据类型
 **/
public class CallableTest implements Callable<String> {
    //2.重写call方法
    private int n;

    public CallableTest(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += i;
        }
        return "子线程执行的结果是" + sum;
    }
}


public class CalableMain {
    public static void main(String[] args) {
        //3.创建任务对象
        Callable<String> call1 = new CallableTest(100);

        /**
         * 4.把Callable任务对象交给FutureTask对象
         * FutureTask的作用1:FutureTask实现了Runnable接口,此时就可以交给Thread了
         * FutureTask的作用2:可以在线程执行完毕后调用get方法得到线程执行的结果
         */
        //Thread t = new Thread(call);  报错,Thread不能接收call对象
        FutureTask<String> f1 = new FutureTask<>(call1);

        //5.交给线程处理
        Thread t1 = new Thread(f1);

        //6.启动线程
        t1.start();

        Callable<String> call2 = new CallableTest(200);
        FutureTask<String> f2 = new FutureTask<>(call2);
        Thread t2 = new Thread(f2);
        t2.start();

        try {
            String rs1 = f1.get();   //直接调用call方法,可能还没有执行完,使用get时若发现线程未执行完会先等线程执行完毕
            System.out.println("第一个结果为:" + rs1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            String rs2 = f2.get();   //直接调用call方法,可能还没有执行完,使用get时若发现线程未执行完会先等线程执行完毕
            System.out.println("第二个结果为:" + rs2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PS:

  • 扩展性强,可以继续继承和实现。
  • 可以在线程执行完毕后获取线程执行的结果。

6.4、Thread常用方法和构造器

Thread提供的常用方法说明
public void run()线程的任务方法
public void start()启动线程
jublic String getName()获取当前线程的名称,线程名称默认是Thread-索引
public void setName(String name)为线程设置名称
public static Thread currentThread()获取当前执行的线程对象
public static void sleep(long time)让当前执行的线程休眠多少毫秒后,再继续执行
public final void join()...让调用当前这个放的线程先执行完
Thread提供的常见构造器说明
public Thread(String name)可以为当前线程指定名称
public Thread(Runnable target)封装Runnable对象成为线程对象
public Thread(Runnable target,String name)封装Runnable对象成为线程对象,并指定线程名称

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

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

相关文章

如何快速搭建一个大模型?简单的UI实现

&#x1f525;博客主页&#xff1a;真的睡不醒 &#x1f680;系列专栏&#xff1a;深度学习环境搭建、环境配置问题解决、自然语言处理、语音信号处理、项目开发 &#x1f498;每日语录&#xff1a;相信自己&#xff0c;一路风景一路歌&#xff0c;人生之美&#xff0c;正在于…

DataGrip 2023.2.3(IDE数据库开发)

DataGrip是一款数据库集成开发环境&#xff08;IDE&#xff09;&#xff0c;用于数据库管理和开发。 DataGrip提供了许多强大的功能&#xff0c;如SQL语句编辑、数据库连接管理、数据导入和导出、数据库比较和同步等等。它支持多种数据库&#xff0c;如MySQL、PostgreSQL、Ora…

Python教程:DataFrame数据中使用resample计算月线平均值

在pandas库中&#xff0c;DataFrame可以使用resample()方法来对时间序列数据进行重采样。重采样是将原始数据按照指定的频率进行重新组织&#xff0c;以便进行更细粒度的分析或转换。下面是一个示例&#xff0c;演示如何使用resample()方法&#xff1a; # Author : 小红牛 # 微…

陶陶摘苹果、跳跃游戏

1. 陶陶摘苹果 题目描述&#xff1a; 陶陶家的院子里有一棵苹果树&#xff0c;每到秋天树上就会结出 10 个苹果。苹果成熟的时候&#xff0c;陶陶就会跑去摘苹果。陶陶有个 30 厘米高的板凳&#xff0c;当她不能直接用手摘到苹果的时候&#xff0c;就会踩到板凳上再试试。 现在…

人力资源管理后台 === 登陆+主页鉴权

目录 1. 分析登录流程 2. Vuex中用户模块的实现 3.Vue-cli代理解决跨域 4.axios封装 5.环境区分 6. 登录联调 7.主页权限验证-鉴权 1. 分析登录流程 传统思路都是登录校验通过之后&#xff0c;直接调用接口&#xff0c;获取token之后&#xff0c;跳转到主页。 vue-elemen…

概念解析 | 玻尔兹曼机

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:玻尔兹曼机。 概念解析 | 玻尔兹曼机 引言 随着人工智能技术的飞速发展,玻尔兹曼机作为一种重要的生成模型,受到了广泛的关注。 背景介绍 玻尔兹曼机(Boltzmann Machine)是一…

vs2019中出现Debug Error的原因

一般出现这种错误表示你的某个变量没有正确赋值&#xff0c;或者说本身在你的C程序中加了assert断言&#xff0c;assert的作用是先计算表达式expression,如果其值为假&#xff0c;那么它会打印一条错误信息 #include<assert.h> void assert(int expression); 例子&…

【23-24 秋学期】NNDL 作业8 卷积 导数 反向传播

习题5-2 证明宽卷积具有交换性&#xff0c; 即公式(5.13)&#xff0e; 图像X和卷积核W的宽卷积定义如下&#xff1a; 要证明&#xff1a;当图像X和卷积核W有固定长度时,他们的宽卷积具有满足交换性&#xff0c;如下&#xff1a; 设二维图像为&#xff1a;&#xff0c;也就是…

【华为OD】B\C卷真题 100%通过:找城市 多叉树实现 python源码

【华为OD】B\C卷真题 100%通过:找城市 多叉树实现 python源码 目录 题目描述&#xff1a; 示例1 示例2 解题思路&#xff1a; 代码实现&#xff1a; 题目描述&#xff1a; 一张地图上有n个城市&#xff0c;城市和城市之间有且只有一条道路相连&#xff1a;要么直接相连&…

Android设计模式--桥接模式

闻正言&#xff0c;行正道&#xff0c;左右前后皆正人 一&#xff0c;定义 将抽象部分与实现部分分离&#xff0c;使它们都可以独立地进行变化 二&#xff0c;使用场景 从模式的定义中&#xff0c;我们大致可以了解到&#xff0c;这里的桥接的作用其实就是连接抽象部分与实现…

如何提高API性能

下图给出了提高API性能的5个常用技巧 分页 当结果很大时&#xff0c;这是一种常见的优化。结果会流回客户端以提高服务响应能力。 异步日志记录 同步日志记录每次调用都会处理磁盘&#xff0c;并且会降低系统速度。异步日志记录首先将日志发送到无锁缓冲区并立即返回。日志将…

肾合胶囊 | 冬不养肾春易病,若出现了这六大表现,小心是肾虚!

冬季作为一年中最寒冷的季节&#xff0c;自然万物皆静谧闭藏&#xff0c;而肾具有潜藏、封藏、闭藏精气的特点&#xff0c;是封藏之本&#xff0c;肾的脏腑特性与冬季相通应&#xff0c;所以在冬季更应该重视养肾。 而现在正值初冬&#xff0c;正是开始养肾的最佳时间。此时培…

2018年3月26日 Go生态洞察:Go包版本管理提案分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Java核心知识点整理大全16-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

4/5G互操作 EPSFB讲解

今天我们来讲一下4/5G之间之间互操作&#xff0c;以及5G的EPSFB是基于什么实现的~ 目录 4/5G互操作 重选 切换 基于覆盖的切换 基于业务的切换 两个面试问题 想要加快4G切换5G的速度&#xff0c;调哪个参数怎么调高效&#xff1f; 想要减慢5G切换4G的速度调哪个参数怎…

STM32 F1 串口空闲中断 + DMA实现数据发送

DMA实现数据发送 文章目录 DMA实现数据发送前言一、DMA二、代码编写1.DMA2.USART3.main 前言 当你遇到通信数据量大的时候&#xff0c;可以使用 空闲中断 DMA 的方案来减轻 CPU 的压力。 或者 在进行stm32开发时&#xff0c;有时会遇到这种情况&#xff1a;需要在设备间进行数…

字符串原地旋转

记录一下做的练习题 字符串原地旋转&#xff1a;五 三 mat [[1,2,3],[3,4,5],[4,5,6]] tag0 total 0 for i in mat:total total i[tag]tag 1 print(total) 四 X [[12,7,3],[4,5,6],[7,8,9]] Y [[5,8,1],[6,7,3],[4,5,9]] res [[0,0,0],[0,0,0],[0,0,0]] for i in rang…

2024年天津天狮学院市场营销专业《管理学》考试大纲

2024年天津天狮学院专升本市场营销专业高职升本入学考试《管理学》考试大纲 一、考试性质 《管理学》专业课程考试是天津天狮学院市场营销专业高职升本入学考试的必考科 目之一&#xff0c;其性质是考核学生是否达到了升入本科继续学习的要求而进行的选拔性考试。《管理学》考…

STM32 默认时钟更改 +debug调试

STM32时钟 文章目录 STM32时钟前言一、修改系统时钟二、DEBUG 前言 为什么我们要改STM32的时钟呢&#xff0c;打个比方在做SPI驱动的时候&#xff0c;需要16M的时钟&#xff0c;但是stm32默认是72的分频分不出来&#xff0c;这个时候我们就要改系统时钟了&#xff0c;那么怎么…

人工智能基础_机器学习050_对比sigmoid函数和softmax函数的区别_两种分类器算法的区别---人工智能工作笔记0090

可以看到最上面是softmax的函数对吧,但是如果当k = 2 那么这个时候softmax的函数就可以退化为sigmoid函数,也就是 逻辑斯蒂回归了对吧 我们来看一下推导过程,可以看到上面是softmax的函数 可以看到k=2 表示,只有两个类别对吧,两个类别的分类不就是sigmoid函数嘛对吧,所以说 …