day37 线程

一、线程安全

二、多线程并发的安全问题

当多个线程并发操作同一临界资源 由于线程切换实际不确定 导致操作顺序出现混乱

产生的程序bug 严重时出现系统瘫痪

临界资源 :操作该资源的完整流程同一时间只能被单一线程操作的资源  

 多线程并发会出现的各种问题、

       如图会出现的各种异常问题

        1. 数组长度不够
        2. 数组下标越界
        3. 0元素过多

两个线程可能会同时读取和修改c.array的长度,从而导致数组长度不一致,进而导致越界异常。在第一个线程使用Arrays.copyOf方法增加数组长度时,第二个线程可能会在此同时读取数组长度,然后在第一个线程修改完成之前,第二个线程又对数组进行了操作,从而导致长度不一致,然后就会出现越界异常。

public class Test {public static void main(String[] args) throws InterruptedException {Coo c = new Coo();Thread t1 = new Thread() {@Overridepublic void run() {synchronized (c){// System.out.println("this1:"+this);for (int i = 0; i < 100; i++) {c.array = Arrays.copyOf(c.array, c.array.length + 1);c.array[c.array.length-1] = i;}}}};Thread t2 = new Thread() {@Overridepublic void run() {synchronized (c){// System.out.println("this:"+this);for (int i = 100; i < 200; i++) {c.array = Arrays.copyOf(c.array, c.array.length + 1);c.array[c.array.length-1] = i;}}}};t1.start();t2.start();/*** 多执行几次,检查程序可能存在的问题,并尝试分析为什么会出现这些情况,以及解决方案**  1. 数组长度不够*  2. 数组下标越界*  3. 0元素过多*///Thread.sleep(1000); //阻塞1秒钟,等待上面两个线程干完活再输出t1.join();t2.join();System.out.println(c.array.length);System.out.println(Arrays.toString(c.array));}
}

 

当一个方法使用synchronized修饰 ,这个方法称之为同步方法,多个线程不能同时在方法内部执行

同步异步的区别 总结来说,同步和异步的区别:请求发出后,是否需要等待结果,才能继续执行其他操作

同步代码块使用的时候需要注意的是同步监视器对象的选择(重点)

1:对象可以是引用数据类型的对象

2:必须保证多个线程看到的对象是同一个

3:在方法上使用synchronized ,那么同步监视器对象就是this,不能自行指定,是默认的

 4: 静态方法上若使用synchronized,则该方法一定具有同步效果
 5注意:静态方法上执行的同步监视器对象不能使用this,而是当前类的类对象

 静态方法中使用同步代码块的锁对象应当是当前类的对象,格式:类名.class
 

 * 类对象:
 *  Class类的一个实例,JVM加载一个类的时候就会实例化一个Class的实例并用于保存加载这个类的
 *  相关信息,因此每个被加载的类都是有且仅有一个Class的实例与之对应,静态方法的锁对象就是它
 *  类对象会在后续的反射知识中详细说明

有限的缩小同步范围可以在保证并发安全的前提下保证效率

互斥锁

当使用多个Synchronized锁定多个代码片段 并且指定的所的对象相同时 这些代码片段就是互斥的

多个线程不能同时调用他们

package com.oracle.day37;public class SynchronizedDemo4 {public static void main(String[] args) {Doo d = new Doo();//    Thread t1 = new Thread(() -> d.methodA());Thread t1 = new Thread(){@Overridepublic void run() {d.methodA();d.methodB();}};
//    Thread t2 = new Thread(() -> d.methodB());Thread t2 = new Thread(){@Overridepublic void run() {d.methodA();d.methodB();}};t1.start();t2.start();}
}
class Doo{public synchronized void methodA()  {Thread t = Thread.currentThread();System.out.println(t.getName()+"正在执行方法A");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(t.getName()+"方法A执行完毕");}public static void methodB() {Thread t = Thread.currentThread();System.out.println(t.getName()+"正在执行方法B");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(t.getName()+"方法B执行完毕");}
}

死锁

在没有释放一把锁的同时调用了另一把锁   

锁中放锁

线程的通讯

每一个线程都是独立运行的状态 但需要多个线程完成同一件事

需要多个线程有规律地运行

线程之间就需要通信,告知对方自己的状态

概念 等待队列 唤醒

相关方法:

 void join()线程进入等待状态 等待另一条线程执行完毕然后继续执行

void wait()释放锁标记,进入等待队列

void wait(long time)释放锁 进入等待队列等待多长时间

void notify()唤醒线程

void notifyAll()唤醒全部线程

package com.oracle.day37.thread;public class ThreadDemo2 {public static Object o = new Object();public static void main(String[] args) {Thread t1 = new Thread(){@Overridepublic void run() {synchronized(o){for (int i = 1; i <= 26; i++) {System.out.println(i);try {o.wait();} catch (InterruptedException e) {e.printStackTrace();}o.notify();}}}};Thread t2 = new Thread(){@Overridepublic void run() {synchronized (o){for (int i = 'A'; i <= 'Z'; i++) {System.out.println((char)i);o.notify();try {o.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}};t1.start();t2.start();}
}

锁的几种形式 

①:方法中添加synchronized修饰符

②:使用同步代码块

        synchronized(){};

* synchronized()可以添加
* this
* Object o
* Shop.class
* "abc"

③:Lock接口

要使用Lock接口,必须在线程中创建并获得Lock对象,然后在需要进行线程同步的代码块中使用lock()方法获取锁,使用unlock()方法释放锁。在多线程环境下,每个线程都必须单独创建自己的Lock对象,并进行锁定和解锁。这种方式可以保证每个线程都能够获取到自己的锁,从而在并发访问时保证线程安全性。

class BuyTicketMethod extends Thread{private static Integer M = 20;private final Lock lock = new ReentrantLock();@Overridepublic  void run() {for (int i = 0; i < 10; i++) {lock.lock();try {if (M > 0){System.out.println("您在"+Thread.currentThread().getName()+"购买成功剩余票是"+(--M)+"张");}} finally {lock.unlock();}}}
}

线程状态(线程的生命周期)

1创建状态:new Thread()对象

2就绪状态:线程对象.start(),线程等待cpu随机分配时间片长度

3运行状态:cpu随机分配给线程执行的cpu时间片

4阻塞状态:暂时让出cpu资源

5死亡状态

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

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

相关文章

聊聊 HTMX 吧

写在前面 最近看了几篇关于 htmx 的文章&#xff0c;自己也去看了一眼官网&#xff0c;也去油管看了一下当时 htmx 发布会的时候他们的演示&#xff0c;下面说几点我对这个所谓的新型起来的技术的看法&#xff0c; 他的来源是什么 首先说一下他虽然是一个新型的技术&#xff0c…

Java 多线程系列Ⅶ(线程安全集合类)

线程安全集合类 前言一、多线程使用线性表二、多线程使用栈和队列三、多线程下使用哈希表 前言 在数据结构中&#xff0c;我们学习过 Java 的内置集合&#xff0c;但是我们知道&#xff0c;我们学过的大多数集合类都是线程不安全的&#xff0c;少数如 Vector&#xff0c;Stack…

小程序分销机制介绍,小程序二级分销功能有哪些?

为什么有越来越多的用户选择使用小程序&#xff1f;跟“高大上”的APP相比&#xff0c;小程序不仅可以减少下载安装的复杂流程&#xff0c;还具备操作便捷、沉淀私域数据的优势。蚓链分销小程序具备裂变二维码、实时分佣、分销身份升级、层级分佣、商品个性化佣金设定等功能&am…

TortoiseSVN 详细操作指南

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 热爱技术的小郑 1、引言 考虑以下几种情况&#xff1a; 你是否在一个…

golang面试题:json包变量不加tag会怎么样?

问题 json包里使用的时候&#xff0c;结构体里的变量不加tag能不能正常转成json里的字段&#xff1f; 怎么答 如果变量首字母小写&#xff0c;则为private。无论如何不能转&#xff0c;因为取不到反射信息。如果变量首字母大写&#xff0c;则为public。 不加tag&#xff0c…

【Spring Cloud系统】- 轻量级高可用工具Keepalive详解

【Spring Cloud系统】- 轻量级高可用工具Keepalive详解 文章目录 【Spring Cloud系统】- 轻量级高可用工具Keepalive详解一、概述二、Keepalive分类2.1 TCP的keepalive2.2 HTTP的keep-alive2.3 TCP的 KeepAlive 和 HTTP的 Keep-Alive区别 三、nginx的keepalive配置3.1 nginx保持…

连接云-边-端,构建火山引擎边缘云网技术体系

近日&#xff0c;火山引擎边缘云网络产品研发负责人韩伟在LiveVideoStack Con 2023上海站围绕边缘云海量分布式节点和上百T的网络规模&#xff0c;结合边缘云快速发展期间遇到的各种问题和挑战&#xff0c;分享了火山引擎边缘云网的全球基础设施&#xff0c;融合开放的云网技术…

数据结构——七大排序[源码+动图+性能测试]

本章代码gitee仓库&#xff1a;排序 文章目录 &#x1f383;0. 思维导图&#x1f9e8;1. 插入排序✨1.1 直接插入排序✨1.2 希尔排序 &#x1f38a;2. 选择排序&#x1f38b;2.1 直接选择排序&#x1f38b;2.2 堆排序 &#x1f38f;3. 交换排序&#x1f390;3.1 冒泡排序&#…

Qt应用开发(基础篇)——工具按钮类 QToolButton

一、前言 QToolButton类继承于QAbstractButton&#xff0c;该部件为命令或选项提供了一个快速访问按钮&#xff0c;通常用于QToolBar中。 按钮基类 QAbstractButton QToolButton是一个特殊的按钮&#xff0c;一般显示文本&#xff0c;只显示图标&#xff0c;结合toolBar使用。它…

【图文并茂】c++介绍之队列

1.1队列的定义 队列&#xff08;queue&#xff09;简称队&#xff0c;它也是一种操作受限的线性表&#xff0c;其限制为仅允许在表的一端进行插入操作&#xff0c;而在表的另一端进行删除操作 一些基础概念&#xff1a; 队尾&#xff08;rear&#xff09; &#xff1a;进行插…

MFC新建内部消息

提示&#xff1a;记录一下MFC新建内部消息的成功过程 文章目录 前言一、第一阶段二、第二阶段三、第三阶段总结 前言 先说一下基本情况&#xff0c;因为要在mapview上增加一个显示加载时间的功能。然后发现是要等加载完再显示时间&#xff0c;显示在主窗口。所以就是在子线程中…

开开心心带你学习MySQL数据库之节尾篇

Java的JDBC编程 各种数据库,MySQL, Oracle, SQL Server在开发的时候,就会提供一组编程接口(API) API ~~ Application Programming Interface ~~ 应用程序编程接口 计算机领域里面的一个非常常见的概念, 给你个软件,你能对他干啥(从代码层次上的) 基于它提供的这些功能,就可以写…

AJAX学习笔记5同步与异步理解

AJAX学习笔记4解决乱码问题_biubiubiu0706的博客-CSDN博客 示例 前端代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>演示AJAX同步和异步</title> </head> <body> <script…

深眸科技自研轻辙视觉引擎,以AI机器视觉赋能杆号牌识别与分拣

电线杆号牌作为电力行业标识的一种&#xff0c;相当于电线杆的“身份证”&#xff0c;担负着宣传电力知识、安全警示的作用&#xff0c;用于户外使用标记输电线路电压等级、线路名称、杆塔编号等&#xff0c;能够清晰地记录电力线路杆的信息&#xff0c;并为电力线路的更改以及…

ChatGPT是如何辅助高效撰写论文及使用ChatGPT注意事项

ChatGPT发布近1年&#xff0c;各大高校对它的态度也发生了极大转变&#xff0c;今年3月发布ChatGPT禁令的牛剑等世界顶级名校也在近期解除了ChatGPT禁令&#xff0c;发布了生成式人工智能使用指南。 ChatGPT一定程度上可以解放科研人员的劳动力&#xff0c;与其直接禁止不如教…

Docker笔记-概念安装简单使用

概念 docker通用词汇。 镜像&#xff1a;Build&#xff0c;创建一个镜像。 仓库&#xff1a;Ship&#xff0c;从仓库和主机上运输镜像。 容器&#xff1a;Run&#xff0c;运行的镜像就是一个容器。 安装 Windows上安装 Docker对win10有原生的支持&#xff0c;win10下的是…

thinkphp6-简简单单地开发接口

目录 1.前言TP6简介 2.项目目录3.运行项目运行命令访问规则 4.model db使用db连接配置model编写及调用调用接口 5.返回json格式 1.前言 基于上篇文章环境搭建后&#xff0c;便开始简单学习上手开发接口…记录重要的过程&#xff01; Windows-试用phpthink发现原来可这样快速搭…

IDEA在创建包时如何把包分开实现自动分层

IDEA在创建包时如何把包分开实现自动分层 文章目录 IDEA在创建包时如何把包分开实现自动分层一、为什么要把包分开二、建包时如何把包自动分开三、如何编写配置文件路径&#xff1f; 一、为什么要把包分开 一开始的时候&#xff0c;我也一直以为包连在一起和分开没什么区别&am…

linux内核模块编译方法之模块编程详解

文章目录 一、模块传参二、模块依赖三、内核空间和用户空间四、执行流五、模块编程与应用编程的比较六、内核接口头文件查询总结 本期和大家主要分享的是驱动开发内核编译过程中对于模块是如何设计的&#xff0c;进行了详细的分享&#xff0c;从模块传参、模块依赖一直到内核空…

Linux dup dup2函数

/*#include <unistd.h>int dup2(int oldfd, int newfd);作用&#xff1a;重定向文件描述符oldfd 指向 a.txt, newfd 指向b.txt,调用函数之后&#xff0c;newfd和b.txt close&#xff0c;newfd指向a.txtoldfd必须是一个有效的文件描述符 */ #include <unistd.h> #i…