day37 线程

news2024/11/18 11:20:23

一、线程安全

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

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

产生的程序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() {
            @Override
            public 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() {
            @Override
            public 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(){
            @Override
            public void run() {
                d.methodA();
                d.methodB();
            }
        };
//    Thread t2 = new Thread(() -> d.methodB());
        Thread t2 = new Thread(){
            @Override
            public 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(){
            @Override
            public 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(){
            @Override
            public 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();
    @Override
    public  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.coloradmin.cn/o/1001584.html

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

相关文章

IT运维:使用数据分析平台监控奇安信

监控目标 本文基于鸿鹄2.10.0版本。 ●监控奇安信日志类型分布 ●监控奇安信攻击行为、分析攻击类型 ●监控奇安信攻击来源情况 操作步骤 数据导入 1、创建数据集&#xff0c;如使用已经存在的数据集&#xff0c;可跳过此步骤 数据集名称&#xff1a;qax_syslog&#xff08;仪表…

管理类联考——数学——汇总篇——知识点突破——应用题——鸡兔同笼

⛲️ 一、考点讲解 第一鸡兔同笼问题 若已知脚数之和及鸡兔总数&#xff0c;求各多少只&#xff1a; 假设全都是鸡&#xff0c;则有 兔数 ( 实际脚数 − 2 鸡兔总数 ) ( 4 − 2 ) 兔数(实际脚数-2鸡兔总数)(4-2) 兔数(实际脚数−2鸡兔总数)(4−2) 假设全都是兔&#xff0…

Python 基础知识:语法、数据类型和控制结构

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 如果开发和环境中已安装 Python&#xff0c;请启动 Python REPL 和代码。或者&#xff0c;如果您想跳过安装并立即开始编码&#xff0c;我建议您前往Google Colab并一起编码。 你好&#xff0c;Python&#xff01; 在…

【算法日志】单调栈: 单调栈简介及其应用

代码随想录刷题60Day 目录 单调栈简介 单调栈的应用 下次更高温 下一个更大元素1 下一个更大元素2 接雨水 柱状图中最大矩形 单调栈简介 单调栈&#xff08;Monotonic Stack&#xff09;是一种特殊的栈数据结构&#xff0c;它满足元素的单调性&#xff0c;这种单调性需…

vue3使用el-form实现登录、注册功能,且进行表单验证(Element Plus中的el-form)

简介&#xff1a;Element Plus 中的 el-form 是一个表单组件&#xff0c;用于快速构建表单并进行数据校验。它提供了丰富的表单元素和验证规则&#xff0c;使表单开发变得更加简单和高效。可以搭配el-dialog实现当前页面的登录、注册页 &#xff0c;这两天在vue3中用到了表单登…

微信小程序 按钮颜色

<button type"primary">主要按钮样式类型</button> <button type"default">默认按钮样式类型</button> <button type"warn">警告按钮样式类型</button> <view>按钮plain是否镂空</view> <bu…

全局光照RSM

Reflective Shadow Maps&#xff08;RSM&#xff09; 一切被直接光照照到的物体&#xff0c;会作为次级光源。 问题1&#xff1a;哪些面片被直接照亮 使用ShadowMap就可以知道哪些面片被直接照亮 问题2&#xff1a;各个面片对P点的贡献分别是多少。 对渲染方程代入如上计算…

CRM客户管理系统能在线使用吗?

经常有朋友私信小编&#xff0c;mac系统/windows系统可以下载使用吗&#xff1f;在哪里下载&#xff1f;其实&#xff0c;Zoho CRM在线即可使用&#xff0c;完全不用下载客户端&#xff01;下面我们就说说&#xff0c;CRM管理系统如何在线用。 Zoho CRM是一款帮助企业进行客户…

恒运资本:什么是五日线?

在股票买卖中&#xff0c;五日线是一种常见的技术剖析指标&#xff0c;用于判别股市的趋势和价格改变。五日线也被称为移动平均线&#xff0c;它是以最近五个买卖日的收盘价为基础核算出的平均值。五日线能够协助出资者识别短期商场意向&#xff0c;及时调整出资战略&#xff0…

Mybatis 框架 ( 四 ) QueryWrapper

4.5.Wrapper条件构造器 Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xff0c;生成 sql 的 where 条件 QueryWrapper &#xff1a; Entity 对象封装操作类&#xff0c;不是用lambda语法 UpdateWrapper &am…

【前端】禁止别人调试自己的前端页面代码

无限debugger 前端页面防止调试的方法主要是通过不断 debugger 来疯狂输出断点&#xff0c;因为 debugger 在控制台被打开的时候就会执行由于程序被 debugger 阻止&#xff0c;所以无法进行断点调试&#xff0c;所以网页的请求也是看不到的代码如下&#xff1a; /** * 基础禁止…

参照错误原因排查

报错如下&#xff0c;弹框参照框不显示&#xff1a; 首先定位到错误代码行&#xff0c;排查后发现调用方式、参数均没问题 再到参照引入源头&#xff0c;结合network检测资源加载情况&#xff0c;发现静态资源js文件均正常获取 可以基本判断是参照组件那边出现问题&#xff0c…

算法通关村第十八关——回溯是怎么回事(青铜)

算法通关村第十八关——回溯是怎么回事&#xff08;青铜&#xff09; 前言1. 从N叉树说起1.1 N叉树的定义和特点1.2 N叉树的遍历方式1.3 N叉树在回溯算法中的应用 2. 为什么有的问题暴力搜索也不行2.1 暴力搜索的局限性 3. 回溯递归局部枚举放下前任3.1 回溯算法的基本思想和原…

运维Shell脚本牛刀小试(九): 重定向操作符“>“及双重定向“>>“

运维Shell脚本小试牛刀(一) 运维Shell脚本小试牛刀(二) 运维Shell脚本小试牛刀(三)::$(cd $(dirname $0)&#xff1b; pwd)命令详解 运维Shell脚本小试牛刀(四): 多层嵌套if...elif...elif....else fi_蜗牛杨哥的博客-CSDN博客 Cenos7安装小火车程序动画 运维Shell脚本小试…

c高级day4(9.11)shell脚本(case ....in语句,循环语句,select ...in和case...In结合,辅助控制关键字,函数)

1.实现一个对数组就和的函数&#xff0c;数组通过实参传递给函数 2.写一个函数&#xff0c;输出当前用户的uid和gid&#xff0c;并使用变量接收结果 #!/bin/bash read -a arr sum0 function add() { …

s2019nh62分数减法

代码&#xff1a; #include<bits/stdc.h> using namespace std; int m1,z1,m2,z2,zd,zx,s1,s2,f1,f2,c,da; int main() {cin>>z1>>m1; //分子1和分母1cin>>z2>>m2; //分子2和分母2zd__gcd(m1,m2); //求两个分母的最大公因数来求最小公倍数z…

数据分析工具有哪些,哪个好学?

Tableau、帆软BI、思迈特BI、SpeedBI数据分析云……这些都是比较常见的BI数据分析工具。从学习成本、操作难度以及数据可视化分析效果来看&#xff0c;SpeedBI数据分析云都表现地可圈可点。 1、不需下载安装、学习成本低 SpeedBI数据分析云是一款SaaS BI数据分析工具&#xf…

IO和进程day05(进程与线程)

今日任务 1.代码 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/wait.h> #include <pthread.h>…

pytorch代码实现之CoordConv卷积

CoordConv卷积 在深度学习领域&#xff0c;几乎没有什么想法能像卷积那样产生如此大的影响。对于任何涉及像素或空间表示的问题&#xff0c;普遍的直觉认为卷积神经网络可能是合适的。在本文中&#xff0c;我们通过看似平凡的坐标变换问题展示了一个惊人的反例&#xff0c;该问…

如何使用bat脚本启动指定目录下的jar包

士别三日&#xff0c;当刮目相待。——《三国志》 为了将一个java程序封装成一个简单易用的小工具&#xff0c;使用bat脚本启动jar包。 在txt文档中&#xff0c;键入&#xff1a; echo off java -jar %~dp0core\demo.jar 注意&#xff1a; 1、其中“core”是文件夹的名称&am…