Java开发:多线程编程

news2025/1/18 9:04:59

本章篇幅主要记录多线程编程相关的知识,如有纰漏,望指出。

话不多说,正式开启多线程之旅...

目录

一、多线程使用方式

A、Thread

B、Runnable(推荐)

C、Callable

二、线程的五个状态

三、线程停止

四、线程休眠sleep

五、线程礼让yield

六、线程插队join

七、线程优先级设置

八、守护线程deamon

九、线程同步

A、数据并发解决办法-synchronized

B、线程安全集合-CopyOnWriteArrayList

C、可重用锁-ReentrantLock

十、死锁

十一、线程池


一、多线程使用方式

A、Thread

使用方法:继承Thread类,不建议使用,避免OOP单继承局限性

示例:多线程下载网络图片

首先,百度搜索导入commonsio.jar,并将jar包导入项目中。


/**
 * 封装下载器
 */
public class FileDownload {
    public void download(String url, String fileName) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(fileName));
        } catch (IOException e) {
            System.out.println("IO异常FileDownload");
        }
    }
}

/**
 * 异步下载网络图片
 */
public class LessonThread1 extends Thread {
    private String url;
    private String fileName;

    public LessonThread1(String url, String fileName) {
        this.url = url;
        this.fileName = fileName;
    }

    @Override
    public void run() {
        FileDownload fileDownload = new FileDownload();
        fileDownload.download(url, fileName);
        System.out.println(fileName + "图片下载完成");
    }
}

/**
 * 执行下载
 */
public class Application {
    public static void main(String[] args) {
        new LessonThread1("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png", "D:\\code\\JavaProject\\Files\\1.jpg").start();
    }

}

B、Runnable(推荐)

使用方法:实现Runnable接口,推荐使用,避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。

示例:龟兔赛跑

public class Race implements Runnable {
    private String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {

            if (Thread.currentThread().getName().contains("兔子") && i % 10 == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            if (gameOver(i)) {
                break;
            }

            System.out.println(Thread.currentThread().getName() + "--->跑了" + i + "步");
        }

    }

    private boolean gameOver(int i) {
        if (winner != null) {
            return true;
        }

        if (i >= 100) {
            winner = Thread.currentThread().getName();
            System.out.println("winner is " + winner);
            return true;
        }
        return false;
    }
}


public class Application {
    public static void main(String[] args) {
        Race race = new Race();
        Thread t1 = new Thread(race, "小兔子");
        Thread t2 = new Thread(race, "乌龟");
        t1.start();
        t2.start();

    }
}

C、Callable

使用方法略

二、线程的五个状态

 

三、线程停止

1、建议线程正常停止--->利用次数,不建议死循环;

2、建议使用标志位进行终止变量 ,当flag= false时终止线程运行--->设置一个标志位;

3、建议使用Thread.interrupt()标志位,原理同方法2;

4、不要使用stop或者destroy等过时API;

public class StopThread implements Runnable {

    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("run thread num --->" + i++);
        }
    }

    private void stop() {
        flag = false;
    }

    public static void main(String[] args) {
        StopThread stopThread = new StopThread();
        new Thread(stopThread).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main thread num --->" + i);
            if (i == 900) {
                stopThread.stop();
                System.out.println("StopThread线程该停止了");
            }
        }
    }
}

四、线程休眠sleep

public class SleepThread {
    public static void main(String[] args) {
        try {
            sleep();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private static void sleep() throws InterruptedException {
        int i = 10;
        while (true) {
            System.out.println(i--);
            Thread.sleep(1_000);
            if (i <= 0) {
                break;
            }
        }
    }

五、线程礼让yield

暂停自己的线程,和其他的线程重新竞争cpu资源

六、线程插队join

插队的线程优先执行,且插队线程执行完成后,其他线程才能继续执行。

七、线程优先级设置

Thread.setPriority(),范围从低到高是1-10

优先级越高,大概率会优先执行。
线程默认优先值为5

八、守护线程deamon

1、线程分为用户线程和守护线程;

2、虚拟机必须确保用户线程执行完毕,但不用等待守护线程执行完毕;

public class DaemonThread {

    public static void main(String[] args) {
        You you = new You();
        God god = new God();


        Thread threadGod = new Thread(god, "上帝");
        threadGod.setDaemon(true);//设置守护线程
        threadGod.start();


        new Thread(you, "你").start();

    }
}

class You implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 30_000; i++) {
            System.out.println("开心的活着");
        }

    }
}

class God implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("上帝保佑着你");
        }
    }
}

九、线程同步

多个线程操作同一个资源,就会造成数据混乱。

A、数据并发解决办法-synchronized

锁的对象:变化的量(并发时共同修改的那个变量)
有两种用法:synchronized方法和synchronized块
缺陷:如果方法加锁会大大影响效率

public class UnsafeList {
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();

        for (int i = 0; i < 10000; i++) {
            new Thread() {
                @Override
                public void run() {
                    //锁代码块,锁的对象是多线程要修改的公共变量
                    synchronized (strings) {
                        strings.add(Thread.currentThread().getName());
                    }

                }
            }.start();
        }
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(strings.size());
    }
}

B、线程安全集合-CopyOnWriteArrayList

public class TestJUC {
    public static void main(String[] args) {
        //位于java.util.concurrent包
        CopyOnWriteArrayList<String> strings = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                strings.add(Thread.currentThread().getName());
            }).start();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(strings.size());
    }
}

C、可重用锁-ReentrantLock

Lock只能锁代码块,synchronized可以锁代码块和方法
 

try{
lock.lock();
//代码逻辑
}finally{
lock.unLock();
}

十、死锁

定义:多个线程互相持有对方需要的资源,然后行程僵持的状态。

产生的条件:

1、一个资源每次只能被一个线程使用;

2、一个线程因请求资源而阻塞时,对已获得的资源保持不放;

3、线程已获得的资源,在未使用之前,不能强行剥夺;

4、若干线程之间形成一种头尾相接的循环等待资源关系;


public class DeadLock {
    public static void main(String[] args) {
        new Makeup(0, "灰姑凉").start();
        new Makeup(1, "白雪公主").start();
    }

}

class Lipstick {
    //口红
}

class Mirror {
    //镜子
}

class Makeup extends Thread {

    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    private int choice;
    private String girlName;

    Makeup(int choice, String girlName) {
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        makeup();
    }

    private void makeup() {
        if (choice == 0) {
            synchronized (lipstick) {
                System.out.println(girlName + "持有口红锁");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                synchronized (mirror) {
                    System.out.println(girlName + "持有镜子");
                }
            }
        } else if (choice == 1) {
            synchronized (mirror) {
                System.out.println(girlName + "持有镜子");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                synchronized (lipstick) {
                    System.out.println(girlName + "持有口红锁");
                }
            }
        }
    }
}

十一、线程池

ExecutorService和Executors
ExecutorService:真正的线程池接口
Executors:工具类、线程池的工厂类

end

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

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

相关文章

LabVIEW性能和内存管理 7 LabVIEW中局部和全局变量的内存分配

LabVIEW性能和内存管理 7 LabVIEW中局部和全局变量的内存分配 本文介绍LabVIEW性能和内存管理的几个建议7。 LabVIEW Cleanup – LabVIEW cleans upmany references when the owning VI goes idle and others when the process closes – Manually closereferences t…

Bean的作用域和生命周期

1. Bean 的作用域 对于全局变量,局部变量等的作用域相信大家都已经很清楚了,但是对于对象作用域有点摸不着头脑,下面通过一个简单的案例,康康对象的作用域 1.1 案例引入 现有一个公共的 Bean 对象 package com.bean.model;import org.springframework.stereotype.Componen…

【IEEE2017】RL:机器人库:一种面向对象的机器人应用程序的方法

RL&#xff1a;机器人库&#xff1a;一种面向对象的机器人应用程序的方法 摘要&#xff1a; 摘要&#xff1a;我们讨论了机器人库&#xff08;RL&#xff09;的架构和软件工程原理。在机器人系统、研究项目、工业应用和教育的需求的驱动下&#xff0c;我们确定了相关的设计需求…

linux上如何搭建Java环境

一 linux软件安装常用的方式对比 Linux下的软件安装&#xff0c;主要有如下三种&#xff0c;“正规”程度依次递减&#xff1a; 1、使用标准的yum/apt/yast包管理程序安装 2、使用标准rpm/deb或厂商自己的安装包&#xff08;比如nVidia的显卡驱动用的bin包&#xff09;安装 …

黑*头条_第2章_文章列表前端成形与后端变身

黑*头条_第2章_文章列表前端成形与后端变身 文章目录黑*头条_第2章_文章列表前端成形与后端变身文章列表前端成形与后端变身学习目标1.前端工程结构1.1 环境准备1.1.1 导入工程1.1.2 测试运行1.2 weex 跨终端前端框架1.3 工程结构说明1.4 源码结构1.5 WEEX UI2.文章列表前端开发…

算法实验题(涉外黄成老师!!!)

日期 2022.11.19 目录 实验报告一 第一题 2 实验报告二 第二题 3 实验报告三 第三题 4 实验报告四 第四题 5 实验报告五 第五题 6 实验报告六 第六题 7 实验报告一 第一题 一、实验目的 由1&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;7&#xff0c;8这六个数字所组…

剑指 Offer II 021. 删除链表的倒数第 n 个结点【链表】

难度等级&#xff1a;中等 上一篇算法&#xff1a; 82. 删除排序链表中的重复元素 II【链表】 力扣此题地址&#xff1a; 剑指 Offer II 021. 删除链表的倒数第 n 个结点 - 力扣&#xff08;LeetCode&#xff09; 1.题目&#xff1a;删除链表的倒数第 n 个结点 给定一个链表&a…

DWGViewX Pro 2021.4.X Crack by Cracki

DWGViewX pro 2021.4.X --Ω578867473 DWGViewX 是一个 ActiveX 组件&#xff0c;可让您在一个查看器中管理和查看 DWG、DXF 和 DWF 工程图。查看 R14 到 2022 版本的 DWG、DXF 和 DWF。加载本地磁盘或网络网站上的图纸&#xff0c;并使用查看器缩放、平移、旋转图纸、打开/关闭…

Java中的线程

线程 什么是线程&#xff1a; 什么是多线程&#xff1a; 学习目的&#xff1a; 多线程的创建 方式一&#xff1a;继承Thread类 public class MyThread{public static void main(String[] args) {Thread thread01 new Thread01();thread01.start();for (int i 0; i < 5; …

翻倍增长!C-V2X商业化“提速”,新一代模组加速“助跑”

C-V2X正在逐步走向商业的规模化部署&#xff0c;由此也带动了C-V2X模组需求的高速增长。 高工智能汽车研究院监测数据显示&#xff0c;今年1-9月中国市场&#xff08;不含进出口&#xff09;乘用车前装标配搭载V2X技术新车交付上险为10.58万辆&#xff0c;同比增长283.33%&…

计算机视觉|投影与三维视觉

这一篇将学习投影与三维视觉&#xff0c;沿用上一篇 计算机视觉|针孔成像&#xff0c;相机内外参及相机标定&#xff0c;矫正的重要性 摄像机内参数矩阵M、畸变参数、旋转矩阵R、平移向量T以及但影响矩阵H。回顾放射和投影变换&#xff0c;并使用POSIT算法从一幅图像中查找获得…

基于stm32单片机有害气体监测检测Proteus仿真

资料编号&#xff1a;097 下面是相关功能视频演示&#xff1a; 97-基于stm32单片机有害气体监测检测Proteus仿真&#xff08;仿真源码全套资料&#xff09;功能介绍&#xff1a;检测当前的有害气体浓度&#xff0c;LCD1602显示&#xff0c;并且可以自动打开关闭风扇&#xff…

Pulsar 各个Shedder分析及新的Shedder -- AvgShedder

看到今年Pulsar 峰会上挺多人分享负载均衡的内容&#xff0c;这里也整理分享一下相关的内容。 社区现有策略的分析 LoadSheddingStrategy pulsar进行shedding的时候&#xff0c;使用的是ThresholdShedder类&#xff0c;ThresholdShedder类是LoadSheddingStrategy接口的其中一…

锐捷SuperVlan实验配置

Super Vlan配置 创建Vlan vlan range 2,3,4,10,20 配置Vlan10为Super Vlan&#xff0c;Vlan 2,3,4为Sub Vlan vlan 10 supervlan subvlan 2,3,4 配置Sub Vlan的地址范围&#xff08;也可以不配置&#xff09; Vlan 2 subvlan-address-range 192.168.10.10 192.168.10.50 配置S…

【数据结构】—时间复杂度or空间复杂度以及基础题目练习

小菜坤日常上传gitee代码&#xff1a;https://gitee.com/qi-dunyan ❤❤❤ 个人简介&#xff1a;双一流非科班的一名小白&#xff0c;期待与各位大佬一起努力&#xff01; 推荐网站&#xff1a;cplusplus.com 目录前言算法与复杂度时间复杂度大O的渐进表示法时间复杂度计算练习…

[附源码]java毕业设计社区疫情防控管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MySQL纯代码复习(上)

前言 本文章是用于总结尚硅谷MySQL教学视频的记录文章&#xff0c;主要用于复习&#xff0c;非商用 原视频连接&#xff1a;https://www.bilibili.com/video/BV1iq4y1u7vj/?p21&spm_id_frompageDriver&vd_sourcec4ecde834521bad789baa9ee29af1f6c https://www.bilib…

【设计模式】 - 创建者模式 -建造者模式

1. 建造者模式 1.1 概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于&#xff1a;某个对象的构建过程复杂的情况。 由于实现了…

小目标检测:基于切图检测的yolov5小目标检测

目前在目标检测方面有着众多的检测框架,比如两阶段的FasterRcnn、以及yolo系列的众多模型。yolo系列在实际中用的最多,一方面性能确实不错,另一方面具有着较多的改进型系列。今天我们主要使用的yolov5系列。具体原理过程就不多说了,大家自行百度。放一张v5的网络结构图。 大…

计算机网络部分(一)

1 请描述 TCP/IP 协议中主机与主机之间通信的三要素 答&#xff1a; IP 地址&#xff08;IP address&#xff09; 子网掩码&#xff08;subnet mask&#xff09; IP 路由&#xff08;IP router&#xff09; 扩展&#xff1a; TCP/IP定义&#xff1a;TCP/IP是基于TCP和IP这两个…