线程的同步

一、互斥锁

  1. java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。
  2. 每个对象都对应与一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有 一个线程访问该对象。
  3. 关键字synchronized用来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
  4. 同步的局限性:导致程序的执行效率降低。
  5. 同步方法(非静态)的锁可以是this,也可以是其他对象(保证是同一个对象)。
  6. 同步方法(静态)的锁为当前类本身,即Dog.class

1.1 同步机制

同步机制是指在对某些共享数据进行访问时,不允许多个线程同时访问导致数据错误,而要求同一时刻只能有一个线程访问共享数据的方法。一般我们通过给访问共享数据区的部分代码上锁的方式来实现同步。上锁之前需要先寻找访问共享数据的那一部分代码,尽量让上锁的代码尽可能的少,提高代码的执行效率。

1.2 生命周期

在线程的生命周期中,官方文档中记录了六个状态。分别是:

状态名说明
NEW尚未启动的线程
RUNNABLE正在java虚拟机中执行的线程
BLOCK受到阻塞并等待某个监视器锁的线程
WAITING无限期等待另一个线程来执行某一特定操作的线程
TIMED WAITING等待另一个指定时间内操作的线程
TERMINATED线程已经结束执行。

其中Runnable状态有很多人又将其分成了正在被CPU执行和等待CPU调度两个状态。当线程由于在等待锁的释放而无法执行时,该线程就处于BLOCK状态。使用下面这段代码可以查看线程的各个状态:

public class ThreadState_ {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        System.out.println(t.getName() +" 状态 "+ t.getState());
        t.start();

        while(Thread.State.TERMINATED != t.getState()){
            System.out.println(t.getName() +" 状态 "+ t.getState());
            Thread.sleep(500);
        }
        System.out.println(t.getName() +" 状态 "+ t.getState());
    }
}

class T extends Thread{
    
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("hi " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

1.3 synchronized 关键字

互斥锁是通过synchronized来修饰方法和代码块来实现,通过使用该关键字修饰方法时有默认的锁对象。当修饰静态方法时,默认的锁对象为当前类.class。当修饰非静态方法时,默认的锁对象是this。使用该关键字修饰代码块时,格式为:

synchronized(锁对象){

}

在选择修饰方法还是修饰代码块时,建议选择修饰代码块,以便提供代码的执行效率。但是使用修饰代码块来上锁时,需要手动选择锁对象。选择锁对象的原则就是要保证多个线程在执行过程中的锁对象必须是同一个对象实例

常用的锁对象分别有:this对象、Object对象、当前类.class。同一个类的不同实例调用的当前类.Class对象是唯一的。而前面两种对象相信大家都比较熟悉,在通过继承Thread类实现多线程时,由于在main方法中会创建多个子线程的实例,因此无法使用synchronized(this)来实现线程的同步。这里通过代码来演示一下该情况无法锁住的情形,其中使用this对象和Object对象都无法锁住,出现了票数超买的情况。

public class SellTicket {
    public static void main(String[] args) {
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();

        //使用synchronize(this), 仍然会出现票数超买现象
        sellTicket01.start();
        sellTicket02.start();
        sellTicket03.start();
    }
}

//使用Thread方式
class SellTicket01 extends Thread{
    private static int ticketNum = 100;
    Boolean loop = true;//线程标志

    public void sell(){
        synchronized (this){//上锁
            if(ticketNum <= 0){
                System.out.println("售票结束...");
                loop = false;
                return;
            }

            //休眠50ms
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName()
                    + " 售出1张票" + "剩余票数 = " + (--ticketNum));
        }
    }
    
    public void run() {
        while (loop){
           sell();
        }
    }
}

超买
而使用当前类.Class则没有出现该情况。当然如果你使用实现Runnable接口的方式来实现多线程,由于只创建了一个线程实例,前面两个锁对象也可以实现同步的效果。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

fpga_pwm呼吸灯(EP4CE6F17C8)

文章目录 一、呼吸灯二、代码实现三、引脚分配 一、呼吸灯 呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化&#xff0c;使用开发板上的四个led灯实现1s间隔的呼吸灯。 二、代码实现 c module pwm_led( input clk ,input rst_n ,output reg [3:0] led ); …

SAP从放弃到入门系列之批次派生-Batch Derivation-Part2

文章目录 一、派生的类型1.1 静态派生1.2 动态派生 二、派生的方向 通过批次派生的基本配置和简单功能的介绍&#xff0c;大家应该对批次派生有一个基本的了解&#xff0c;这篇文章从批次派生的类型和批次派生的方向两个维度更深入的聊一下它的功能。 一、派生的类型 派生的类…

Vue 渲染流程详解

在 Vue 里渲染一块内容&#xff0c;会有以下步骤及流程&#xff1a; 第一步&#xff0c;解析语法&#xff0c;生成AST 第二步&#xff0c;根据AST结果&#xff0c;完成data数据初始化 第三步&#xff0c;根据AST结果和DATA数据绑定情况&#xff0c;生成虚拟DOM 第四步&…

Spring Cloud【为什么需要监控系统、Prometheus环境搭建、Grafana环境搭建 、微服务应用接入监控 】(十七)

目录 全方位的监控告警系统_为什么需要监控系统 全方位的监控告警系统_Prometheus环境搭建 全方位的监控告警系统_Grafana环境搭建 全方位的监控告警系统_微服务应用接入监控 全方位的监控告警系统_为什么需要监控系统 前言 一个服务上线了后&#xff0c;你想知道这个服…

Leetcode 114. 二叉树展开为链表

题目描述 题目链接&#xff1a;https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/description/ 思路 先序遍历展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 List list …

Oracle 迁移 Hive 过程中遇到的问题总结

前言 最近一个小伙伴在做从 Oracle 到 Hive 的业务迁移工作,在迁移过程中属实遇到了一些坑,今天就来汇总一下这些坑,避免以后大家其他业务迁移的时候再出现类似的问题,即使出现了也可以拿过来进行对照解决。 问题1:Distinct window functions are not supported: count(…

shell 脚本通过 dumpsys SurfaceFlinger --latency 数据计算 FPS 和评价流畅度。

目录 前言&#xff1a; 开篇前述&#xff1a; 一、设计初衷 二、设定预期倒推查找解决方案 设计实现部分 一、确定数据来源原因&#xff08;dumpsys SurfaceFlinger --latency&#xff09; 二、根据需求确定计算规则 三、代码实现 四、监控数据可视化交互结果设计 前言…

ES6基础知识二:ES6中数组新增了哪些扩展?

一、扩展运算符的应用 ES6通过扩展元素符…&#xff0c;好比 rest 参数的逆运算&#xff0c;将一个数组转为用逗号分隔的参数序列 console.log(...[1, 2, 3]) // 1 2 3console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5[...document.querySelectorAll(div)] // [<div>, &l…

APISIX 安全评估

背景 有大佬已经对 [apisix攻击面](https://ricterz.me/posts/2021-07-05-apache-apisix-attack- surface-research.txt)做过总结。 本文记录一下自己之前的评估过程。 分析过程 评估哪些模块&#xff1f; 首先我需要知道要评估啥&#xff0c;就像搞渗透时&#xff0c;我得…

Websocket协议-http协议-tcp协议区别和相同点

通讯形式 单工通讯-数据只能单向传送一方来发送数据&#xff0c;另一方来接收数据 半双工通讯-数据能双向传送但不能同时双向传送 全双工通讯-数据能够同时双向传送和接受 注&#xff1a;http的通讯方式是分版本 http1.0&#xff1a;单工。因为是短连接&#xff0c;客户端…

【设计模式——学习笔记】23种设计模式——建造者模式Builder(原理讲解+应用场景介绍+案例介绍+Java代码实现)

介绍 建造者模式又叫生成器模式&#xff0c;是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别)&#xff0c;使这个抽象过程的不同实现方法可以构造出不同属性的对象建造者模式是一步一步创建一个复杂的对象&#xff0c;它允许用户只通过指定复杂对象的类型和…

C 程序 运算符

文章目录 1、算术运算符2、关系运算符3、逻辑运算符4、位运算符5、赋值运算符6、杂项运算符 ↦ sizeof & 三元7、运算符优先级 1、算术运算符 #include <stdio.h>int main() {int a 21;int b 10;int c ;c a b;printf("Line 1 - c 的值是 %d\n", c );c …

【mac系统】mac系统调整妙控鼠标速度

当下环境&#xff1a; mac系统版本&#xff0c;其他系统应该也可以&#xff0c;大家可以自行试下&#xff1a; 鼠标 mac妙控鼠标&#xff0c;型号A1657 问题描述&#xff1a; 通过mac系统自带的鼠标速度调节按钮&#xff0c;调到最大后还是感觉移动速度哦过慢 问题解决&…

Cesium态势标绘专题-矩形(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

网站实现下载apk安装包

目录 1、背景说明2、效果图3、具体实现3.1 界面代码3.2 js代码 4、说明4.1 存在异常4.2 解决方案 5、参考资料 1、背景说明 有时需要将写好的apk安装包在局域网内部进行发布&#xff0c;具体实现非常简单&#xff0c;如下所示 2、效果图 进入到网站后&#xff0c;点击下载按…

STM32MP157驱动开发——按键驱动(tasklet)

文章目录 “tasklet”机制&#xff1a;内核函数定义 tasklet使能/ 禁止 tasklet调度 tasklet删除 tasklet tasklet软中断方式的按键驱动程序(stm32mp157)tasklet使用方法&#xff1a;button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “tasklet”机制&#xff1a; …

Stable Diffusion服务环境搭建(远程服务版)

Stable Diffusion服务环境搭建&#xff08;远程服务版&#xff09; Stable Diffusion是什么 Stable diffusion是一个基于Latent Diffusion Models&#xff08;潜在扩散模型&#xff0c;LDMs&#xff09;的文图生成&#xff08;text-to-image&#xff09;模型。具体来说&#…

学生公寓报修管理系统的设计与实现(论文+源码)_kaic

摘 要 随着科技的发展&#xff0c;信息化的管理手段早以在人们生活的各个方面取代了传统的管理手段&#xff0c;以先进管理理念为基础的现代化信息管理系统已经成为了许多机构的必备工具。在如今大学的校园里&#xff0c;有着许许多多的信息化管理系统&#xff0c;如图书管理系…

前端面试题汇总大全!

文章目录 前端面试题汇总大全&#xff08;含答案超详细&#xff09;-- 持续更新一、HTML 篇1.xhtml和html有什么区别2.行内元素有哪些&#xff1f;块级元素有哪些&#xff1f; 空(void)元素有那些&#xff1f;行内元素和块级元素有什么区别3. 简述一下你对 HTML 语义化的理解&a…

【数学建模】为什么存在最优策略?

一、说明 在进行优化回归过程&#xff0c;首先要看看是否存在最优策略&#xff1f; 在有限马尔可夫决策过程 &#xff08;MDP&#xff09; 中&#xff0c;最优策略被定义为同时最大化所有状态值的策略。换句话说&#xff0c;如果存在最优策略&#xff0c;则最大化状态 s 值的策…