[java进阶]——多线程Thread类,处理并发异常的方法

news2024/9/20 1:03:05

🌈键盘敲烂,年薪30万🌈

目录

一、理解进程与线程

二、Thread类

三、自定义线程的三种实现方式

四、多线程应用场景

五、解决并发问题的方法

5.1 synchronized()关键字 - 同步代码块

5.2使用lock锁


一、理解进程与线程

运行一个程序占用一个进程,程序中的子任务是线程,故一个进程可以有多个线程。

例如银行每一个窗口都在处理业务,但所有窗口存和取的钱都放在该银行保险柜里

 🐒当下最火的并发编程

一个线程在运行时是会占用cpu内存的,如果该线程正待等待用户输入数据,那么用户不输入,cpu就要一直被占用,为了提高cpu的利用率,有了并发执行,线程抢占cpu,每个线程被选中执行的概率是随机的,这叫线程调度

拓展个概念:

每个线程被cpu选中执行的概率是随机的,这个过程叫做线程的调度,线程调度器会根据线程的优先级、执行状态、等待时间等因素来决定哪个线程可以被执行,从而实现对CPU资源的有效利用。

4核8线程的意思是有四个独立的核心一个核心有2个线程,每个任务可以在不同的核心上执行,每个任务的一个子任务就可以看作一个线程。

mian函数也是一个线程。

二、Thread类

java把线程相关的属性和方法封装到Thread类里面,可以利用该类创建线程对象

start 开启线程

setname 设置名称

getname 获取名称

sleep 休眠多少毫秒(静态)

currentThread 获取当前线程(静态)

setPriority 设置线程的优先级

setDaemon 设置为守护线程

🐒初步感受进程代码

class MyThread extends Thread{
    @Override
    public void run() {
        while (true){
            System.out.println("我是另一个线程");
            //休眠2秒
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        while (true){
            Thread.sleep(2000);//休眠两秒
            System.out.println("main线程");
        }


    }
}

main线程和另一个线程交替执行。

三、自定义线程的三种实现方式

3.1创建一个类继承Thread子类

重写里面的run方法 - 线程要处理的任务

创建该类

public class MyThread extends Thread{
    @Override
    public void run() {
        //线程要执行的方法
    }
}
public static void main(String[] args) {
        /*
        * 线程的第一种创建方式thread
        * 1.创建一个类继承thread
        * 2.重写里面的run方法
        * 3.创建该类
        *
        *
        * */

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

    }

3.2定义一个runable接口的实现类

重写run方法

创建runable实现类

据实现类创建Thread类

public class MyRun implements Runnable{
    @Override
    public void run() {
        //线程要执行的方法
    }
}
public static void main(String[] args) {
        /*
        * 线程的第二种实现方式
        * 1.定义一个类实现runable接口
        * 2.创建该接口的实现类
        * 3.创建thread类,把实现类传入
        * */
        MyRun myRun = new MyRun();
        Thread thread = new Thread(myRun);
    }

3.3定义一个类实现callable接口

重写call方法

创建callable实现类 - 任务

创建futuretask对象 -  管理线程结果

创建thread对象 - 创建线程

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        //线程要执行的方法
        return total;
    }
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        * 多线程的第三种实现方式
        * 1.定义一个类实现callable接口
        * 2.重写里面的call方法
        *
        * 3.创建mycallable对象 - 任务
        * 4.创建futuretask对象 - 管理线程结果
        * 5.创建thread对象 - 创建线程
        *
        * */
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(myCallable);
        Thread thread = new Thread(integerFutureTask);

    }

3.4应用场景总结

如果要用到线程的处理结果(返回值),就用第三种实现方法

如果你想继承其它子类,用第二种或第三种

如果是单纯的继承Thread类,用第一种

因为java只支持单继承,不支持多继承

四、多线程应用场景

🖌用多线程模拟三个窗口卖100张票的过程

思路:1.定义一个线程类  2.重写里面的run方法模拟买票  3.创建3个对象模拟3个窗口

public class Mythread extends Thread {
    static int ticket = 0;//静态修饰
    @Override
    public void run() {
        while (ticket++ < 100) {
                try {
                    //休眠1秒
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "窗口正在卖第" + ticket + "张票");
            }
    }
}
public class Test1 {
    public static void main(String[] args) {
        //实现三个窗口卖100张票的
        Thread t1 = new Mythread("窗口1");
        Thread t2 = new Mythread("窗口2");
        Thread t3 = new Mythread("窗口3");
        t2.start();
        t1.start();
        t3.start();
}

我们把代码跑起来

这和现实生活中的完全不一样,这其实引发了并发异常,简单说一下,开启了3个进程,每个进程被cpu选中是随机的,当线程1被选中并且代码运行到while循环里,cpu又去执行线程2,还有可能去执行线程三等等,所以导致同时卖出了第三张票

五、解决并发问题的方法

5.1 synchronized()关键字 - 同步代码块

原理分析:

给可能发生异常的代码加上锁之后,其他线程只能等待该线程执行完释放该锁。

代码分析:

synchronized()

括号要求是一个对象,什么类型都可,但针对该类必须唯一,也就是这把锁是管理该类的一把锁,可以是静态修饰得对象,可以是Mythread得字节码文件。

还是以买票举例

public class Mythread extends Thread {
    static int ticket = 0;//静态修饰
    @Override
    public void run() {
        while (ticket++ < 100) {
            //synchronized()括号里写一个锁对象,必须针对该类唯一
            synchronized (Mythread.class) {
                try {
                    //休眠1秒
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "窗口正在卖第" + ticket + "张票");
            }
        }
    }
}

把可能引发并发异常的代码抽象成方法 用synchronized修饰

这是的锁对象会默认创建,如果是静态的方法,该对象是ths 如果是非静态,该对象是该类的class文件

@Override
    public void run() {
        while (ticket++ < 100000) {
            //同步方法
            method();
        }
    }

    private synchronized void method() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "窗口正在卖第" + ticket + "张票");
    }

5.2使用lock锁

获取静态锁对象

调用lock方法把并发代码锁起来

并发代码用try-catch包裹

释放锁放在finally代码块里

public class MyThread extends Thread{
    static int ticket = 0;
    static Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while(ticket++ <= 100){
            lock.lock();
            try {
                if(ticket <= 100){
                    System.out.println(Thread.currentThread().getName() + "窗口卖出第" + ticket + "张票");
                    Thread.sleep(10);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

    }
}

这样修改后的买票系统就能正常实现啦

注意:不要使用锁嵌套,可能出现死锁。看下面代码

public class DeadlockExample {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread 1 acquired lock1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("Thread 1 acquired lock2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread 2 acquired lock2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("Thread 2 acquired lock1");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

📕总结

为什么会有并发异常,并发异常会导致什么后果

如何解决并发异常

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

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

相关文章

VS Code设置代码自动保存

给新电脑安了VS Code&#xff0c;提交运行代码前总是忘了保存&#xff0c;之前的电脑里是设置了自动保存按钮&#xff0c;所以导致我在新电脑上总是忘了。特记录VS Code设置自动保存功能。 首先在右下角找到“设置”按钮 然后在输入框输入“auto save”进行查找 可以看到自动…

Centos磁盘爆满_openEuler系统磁盘爆满清理方法---Linux工作笔记060

磁盘爆满,监控部门就会报警,报警就要处理,但是程序员并不擅长做运维的工作,记录一下把...以后用到会方便: 使用df -h命令可以看到,对应的磁盘占用情况,这里我的/dev/mapper/openeuler-root这个目录 占用的磁盘比较多,到了百分之95了.. 往往就是这个跟目录,我这里/data目录是自…

CSDN提供的Markdown常用模板

标题 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持&#xff0c;除了标准的Markdown编辑器功能&#xff0c;我们增加了如下几点新功能&#xff0c;帮助你用它写博客&#xff1a; 全新的界面设计 &#xff0c;将会带来全新的写作体验&#xff1b;在创作中心设置…

1024程序员节特辑:【Spring Boot自动配置原理揭秘】

自动配置原理 概述原理Spring Boot Starterspring.factories 文件ConditionalOnX 注解配置 Bean配置属性 源码剖析复合AnnotationEnableAutoConfigurationAutoConfigurationImportSelector 主页传送门&#xff1a;&#x1f4c0; 传送 概述 Spring Boot 是一个用于创建独立的、…

.rancher-pipeline.yml

一、注意点 其实下文二的image是基于这个镜像作为基础镜像在这个镜像中执行打包&#xff0c;shellScript 当前路径是你代码块与上图settings.xml&#xff0c;图中的settings.xml可以替换下你当前镜像的settings.xml 示例 二、.rancher-pipeline.yml ${CICD_GIT_BRANCH}这些从官…

天下苦定制久矣,平台化建设到底难在哪里?

为什么需要平台 随着业务的不断发展&#xff0c;软件系统不可避免的走向熵增&#xff1a;复杂度越来越高、研发效率越来越差、稳定性逐渐降低等。这时抽象核心能力&#xff0c;走向平台化的道路成为很多系统的首要选择 平台的建设目标 产品的核心价值在于其有效性和用户体验…

视频号视频如何下载(WeChatVideoDownloader)

背景介绍 最近需要一个视频号里面的视频进行宣传用&#xff0c;网上找了很多方法都不行&#xff0c;特别是下载抓包工具Fiddler&#xff0c;然后监控HTTPS请求的&#xff0c;截取URL把URL中20302改成20304&#xff0c;再用IDM工具下载对应的资源&#xff0c;最后修改后缀名.mp…

《红蓝攻防对抗实战》三.内网探测协议出网之HTTP/HTTPS协议探测出网

目录 一. 在 Windows 操作系统中探测 HTTP/HTTPS 出网 1. Bitsadmin 命令 2.Certuil 命令 2.Linux系统探测HTTP/HTTPS出网 1.Curl命令 2.Wget命令 对目标服务器探测 HTTP/HTTPS 是否出网时&#xff0c;要根据目标系统类型执行命令&#xff0c;不同类型的操作系统使用的探…

GeoServer改造Springboot源码一(公共部分)

今天开始开启关于GeoServer的一个全新系列,主要是把改造Springboot后的详细代码粘贴出来,此文应配合《GeoServer改造Springboot启动》系列共同阅读,按照前系列的时间顺序结合此系列的源码展示可以快速构建GeoServer功能的二次封装的后端系统。 一、Springboot部分源码结构 …

NC资金管理相关问题

1、差旅费借款单支付单位是另外一家公司&#xff0c;审批后自动签字&#xff0c;审批时报错是为什么&#xff1f;报错信息是&#xff1a;没有当前资源的操作权限。 答&#xff1a;用户没有结算节点支付单位的权限&#xff0c;所以当无权限进行自动签字。 2、收付款单在结算节点…

如何破解压缩包密码,CTF压缩包处理

I. 引言 压缩包我们经常接触&#xff0c;用于对文件进行压缩存储/传输。压缩包处理在CTF比赛中是非常重要的一块&#xff0c;因为压缩包中可能包含重要信息&#xff1a;许多CTF题目会将关键信息隐藏在压缩包中&#xff0c;参赛者需要解压并查看其中的内容才能获取有用的线索。…

自动巡查、自动换充电……浙江这两台无人机“巢穴”派大用场

浙江省积极探索利用高科技的无人机技术提高森林防火效率。在杭州市西湖区的西山国家森林公园和绍兴市柯桥区的大香林风景区&#xff0c;部署了两台复亚智能全自动无人机飞行系统&#xff0c;实现了火情的自动检测、定期自动巡查以及迅速响应。该技术的应用标志着杭州从传统的“…

设计院图纸加密防泄密方案——天锐绿盾加密软件@德人合科技

天锐绿盾是一款专业的企业信息化防泄密软件&#xff0c;主要针对文档全生命周期进行加密保护&#xff0c;包括创建、修改、传输、归档、分发、销毁等全过程。它可以加强外发数据及终端离线的管理&#xff0c;对正常授权外带范围内的数据流程进行规范。设计图纸、文档等成果数据…

2023年英特尔on技术创新大会深度解析

在北京时间9月19日23&#xff1a;35分&#xff0c;Intel在美国加州圣何塞举办了2023英特尔on技术创新大会。在会议上&#xff0c;Intel相关负责人进行发言&#xff0c;并阐释了本次会议的三大重点内容&#xff0c;分别为Intel Meteor Lake架构概览&#xff0c;Intel 4制程工艺与…

安卓sd卡格式化数据恢复方法,您了解吗

随着智能手机的广泛使用&#xff0c;SD卡作为一种存储扩展设备&#xff0c;已经成为了安卓手机用户的必备之选。然而&#xff0c;当SD卡意外格式化&#xff0c;存储在其中的重要数据也会随之消失。那么&#xff0c;安卓SD卡格式化后数据丢失怎么办&#xff1f;本文将介绍安卓SD…

leetcode 21

递归的方式 class Solution { public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(l1 nullptr){return l2;}else if(l2 nullptr){return l1;}else if(l1->val < l2->val){l1->next mergeTwoLists(l1->next, l2);return l1;}else if(l1->va…

通讯网关软件029——利用CommGate X2MQTT实现MQTT访问DDE数据源

本文介绍利用CommGate X2MQTT实现MQTT访问DDE数据源。CommGate X2MQTT是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现上位机通过MQTT来获取DDE数据源的数据。 【解决方案】设置网关机&…

StarCCM+引入第三方库,找不到的错误

StarCCM里自定义的宏文件是在Star里编译运行的&#xff0c;第三方库需要单独引用。工具->options->环境->用户宏类路径 点进去以后&#xff0c;一定要注意多个jar包是写在一行的&#xff0c;不要主动换行。

6款好用到爆的神级电脑软件,个个让人相见恨晚,堪称办公必备

你的电脑上有哪些好用到爆的神级电脑软件&#xff1f;今天就给大家分享6款好用到爆的神级电脑软件&#xff0c;个个让人相见恨晚&#xff0c;堪称办公必备。 1、PDF工具&#xff1a;PDF24 Tools PDF24 Tools是一款强大而多功能的PDF工具集合&#xff0c;提供了许多便捷的功能&a…

Shopee买家通系统一款批量注册虾皮买家号软件

如果想要大量的虾皮买家号&#xff0c;那么可以使用shopee买家通系统进行全自动化的注册&#xff0c;这款软件在注册时可以自动输入手机号、自动接收短信并输入、自动设置密码等&#xff0c;方便又快速。 shopee买家通系统支持多个国家使用&#xff0c;可以用于菲律宾、印度尼西…