Java关键词synchronized

news2024/9/20 10:55:49

目录

一、通过卖票系统观察多线程的安全隐患

二、synchronized的基本知识

1.使用synchronized的原因

2.synchronized的作用

3.synchronized的基本格式

  a.synchronized加在方法名前

  b.synchronized用在方法中

4. Java锁机制

5.synchronized注意事项

三、使用synchronized修改卖票系统代码


一、通过卖票系统观察多线程的安全隐患

public class Tickets {
    int num;

    public Tickets(int num) {
        this.num = num;
    }

    public int getNum() {
        return this.num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
public interface TicketService {
    public void sale();
}
public class SaleTickets implements TicketService {
    private Tickets tickets;

    public SaleTickets() {

    }

    public SaleTickets(Tickets tickets) {
        this.tickets = tickets;
    }

    public void sale() {
        int num = tickets.getNum();
        System.out.println(Thread.currentThread().getName() + "正在出库第" + num + "张票,剩余" + --num + "张票");
        tickets.setNum(num);
    }
}
public class Window {
    public static void main(String[] args) {
        Tickets tickets = new Tickets(50);
        TicketService saleTickets = new SaleTickets(tickets);
        new Thread(() -> {
            while (tickets.getNum() > 0) {
                saleTickets.sale();
            }
        },"窗口1").start();
        new Thread(() -> {
            while (tickets.getNum() > 0) {
                saleTickets.sale();
            }
        },"窗口2").start();
    }
}

运行结果:

运行结果中出现重复出售票数的现象,因此需要了解synchronized关键词的操作来解决这一问题

二、synchronized的基本知识

1.使用synchronized的原因

        当多个线程共享一个数据时,如果处理不当,很容易出现线程的安全隐患,比如丢失修改、不可重复读、读脏数据等,所以多线程编程时经常要解决线程同步问题。

2.synchronized的作用

        当某个对象用synchronized修饰时,表明该对象在任何时刻都只能由一个线程访问。当一个线程进人synchronized方法后,能保证在任何其他线程访问这个方法之前完成自己的执行。如果一个线程试图访问一个已经启动的synchronized方法,则这个线程必须等待,直到已启动线程执行完毕,再释放这个synchronized方法。

3.synchronized的基本格式

  a.synchronized加在方法名前

 public synchronized void Method1() {// (访问权限修饰符+synchronized+返回值类型+方法名)
        /* 方法体 */
    }

  b.synchronized用在方法中

 public void Method2() {// (访问权限修饰符+返回值类型+方法名)
        synchronized (this) {
            /* 代码块 */
        }
    }

4. Java锁机制

        Java使用锁机制保证同步代码块或方法的“原子性”,即保持整体性,不可分隔。Java中每个对象都有一个内置锁,只有当对象具有同步代码时,内置锁才会起作用。当进人一个同步方法时,线程自动获得方法所在类的当前实例相关的锁,即给this对象加锁。当同步代码块或同步方法执行完毕后,同步对象上的锁就被解除,该线程就有机会获取该对象的锁。

5.synchronized注意事项

a.如果synchronized用在类声明中,则表明该类中的所有方法都是synchronized的。

b.锁不属于线程,而是属于对象,一个线程可以拥有多个对象的锁,而只有同一个对象之间的锁才会互斥。

三、使用synchronized修改卖票系统代码

        并发环境下,对每个请求创建了多个线程去处理。这段对统计变量操作的代码,曝露在多线程环境下,却没有任何同步处理,从而导致重复卖票问题。

public class Tickets {
    int num;

    public Tickets(int num) {
        this.num = num;
    }

    public int getNum() {
        return this.num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}
public interface TicketService {
    public void sale();
}
public class SaleTickets implements TicketService {
    private Tickets tickets;

    public SaleTickets() {

    }

    public SaleTickets(Tickets tickets) {
        this.tickets = tickets;
    }

    public void sale() {
        synchronized (this) {
            int num = tickets.getNum();
            if (num > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出库" + num + "张票,剩余" + --num + "张票");
                tickets.setNum(num);
            }
        }
    }
}
public class Window {
    public static void main(String[] args) {
        Tickets tickets = new Tickets(50);
        TicketService saleTickets = new SaleTickets(tickets);
        new Thread(() -> {
            while (tickets.getNum() > 0) {
                saleTickets.sale();
            }
        },"窗口1").start();
        new Thread(() -> {
            while (tickets.getNum() > 0) {
                saleTickets.sale();
            }
        },"窗口2").start();
    }
}

运行结果: 

 此时运行结果中没有出现重复出售票的现象

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

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

相关文章

【可变参数列表如何可变?】

可变参数列表 本章重点 学会使用可变参数列表的使用与原理 函数传参补充知识 如果函数没有形式参数,仍然可以给函数传递参数。在c语言中,只要发生了函数调用并且传递了函数,必定形成临时变量。所谓的临时拷贝本质就是在栈帧内部形成的&#…

Tcl常用命令备忘录-基础篇

一、置换 1、变量置换 在Tcl中,$符号可以用来引用变量。变量置换可以用来将变量的值嵌入到代码中。例如: set name "Tom" puts "Hello, $name!"这个示例中,变量$name的值会在输出语句中被替换为"Tom"。 2…

腾讯云服务器镜像市场快速搭建WordPress博客网站教程

通过腾讯云服务器的镜像市场搭建WordPress网站非常简单,不需要手动配置WP所需的Web环境,一键即可安装WordPress博客,腾讯云百科使用腾讯云服务器通过镜像市场的WordPress镜像搭建WP网站教程: 目录 腾讯云服务器通过市场镜像安装…

SpringMvc拦截器和手写模拟SpringMvc工作流程源码详解

目录 1. SpringMvc简介 1.1 什么是MVC 1.2 什么是SpringMvc 1.3 SpringMvc 能干什么 1.4 SpringMvc 工作流程 2. SpringMvc拦截器和过滤器 2.1 拦截器 2.1.1 拦截器作用 2.1.2 拦截器和过滤器的区别 2.1.3 拦截器方法说明 2.1.4 多个拦截器执行顺序 2.1.5 自定义拦…

29 虚拟地址到物理地址的转换

前言 呵呵 这是 linux 中内存管理中很基础的一环 用户程序 操作的地址都是虚拟地址, 虚拟地址通过 mmu 转换为物理地址 用户程序 看到的地址都是一个完整的世界, 只有具体需要使用的时候 产生缺页中断, 然后 分配具体的物理页 这里 要说的就是 虚拟地址 到 物理地址 的转…

1001router6-react

文章目录 1 一级路由2 Navigate3 NavLink 自定义高亮样式4 useRoutes()5 嵌套路由6 路由传参6.1 传递params参数6.2 传递search参数6.3 传递state参数 7 编程式导航7.1 路由跳转7.2 前进、后退 8 钩子函数8.1 useInRouterContext()8.2 useNavigationType()8.3 useOutlet()8.4 u…

手写Spring框架---AOP实现

目录 容器是OOP的高级工具 系统需求 关注点分离Concern Separation 原有实现 AOP的成员 Advice的种类 单个Aspect的执行顺序 多个Aspect的执行顺序 Introduction-引入型Advice 代理模式 JDK动态代理 Spring AOP的实现原理之JDK动态代理 Spring AOP的实现原理之CGL…

CSS基础学习--19 下拉菜单

一、基本下拉菜单 当鼠标移动到指定元素上时&#xff0c;会出现下拉菜单 <!DOCTYPE html> <html> <head> <title>下拉菜单实例</title> <meta charset"utf-8"> <style> .dropdown {position: relative;display: inline-…

UnityVR-项目的管理阶层

目录 概述 项目的总体架构 单例基类 继承MonoBehaviour的单例基类 概述 一个具备一定规模的项目&#xff0c;一般都需要由不同人员合作完成&#xff0c;每个人的想法风格不相同&#xff0c;如果一开始没有定下基本的框架&#xff0c;会让实现时混乱不堪&#xff0c;而且无法…

【CesiumJS入门】(5)GooJSON的加载、更新、监听与销毁——GeoJsonDataSource应用

前言 本篇&#xff0c;我们将较完整得介绍Cesium中GeoJSON/TopoJSON相关的方法。 GeoJSON规范地址&#xff1a;RFC 7946: The GeoJSON Format (rfc-editor.org) GeoJSON在线绘制&#xff1a;geojson.io CesiumJS提供了一个名为DataSource的类&#xff0c;它主要是用来加载和展…

Java-API简析_java.util.UUID类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/131270140 出自【进步*于辰的博客】 其实我的【Java-API】专栏内的博文对大家来说意义是不大的。…

《计算之魂》读书笔记——递归与堆栈的关系

进入梅雨季节&#xff0c;一周末雨水连绵不绝&#xff0c;空气中泛着潮湿的凉爽。这个天气最适合找个角落&#xff0c;安安静静地读书写字。 继续读《计算之魂》&#xff0c;前次读到递归&#xff0c;今天则了解递归地数据结构实现。递归算法的层层实现&#xff0c;需要保留从…

大数据周会-本周学习内容总结018

开会时间&#xff1a;2023.06.18 15:00 线下会议 01【调研-数据分析&#xff08;质量、ETL、可视化&#xff09;】 ETL&#xff0c;是英文Extract-Transform-Load的缩写&#xff0c;用来描述将数据从来源端经过抽取&#xff08;extract&#xff09;、转换&#xff08;transform…

Tcl常用命令备忘录-正则命令篇

正则表达式是一种用于匹配、查找、替换文本中特定模式的工具。在Tcl脚本中&#xff0c;可以使用正则表达式对字符串进行匹配、查找和替换。 regexp 语法&#xff1a; regexp ?选项? 正则表达式 字符串 ?变量1 变量2 ...? 其中&#xff0c;?选项?为可选项&#xff0c;…

基于蒙特卡洛法的规模化电动汽车充电负荷预测(PythonMatlab实现)

目录 0 概述 1 蒙特卡洛模拟方法介绍 2 规模化电动汽车充电负荷预测计算方法 3 完整代码 0 概述 对于本文的研究,依据不同用途电动汽车影响因素的分布函数和设定参数&#xff0c;采用蒙特卡洛法,对各用途电动汽车的日行驶里程、起始充电时间概率分布参数进行随机抽样&#xff0…

linuxOPS系统服务_Linux下软件的安装方式之源码安装

Linux下有哪些软件安装方式 ① RPM软件包管理&#xff08;软件名称.rpm&#xff09; ② YUM软件包管理&#xff08;使用yum命令install 软件名称&#xff09; > 下载 安装一体化 ③ 源码编译安装&#xff08;相对来说是最复杂的一种方式&#xff09; 软件包类型 ☆ 二…

十二、docker学习-docker核心docker网络之bridge网络(2)

bridge网络 bridge网络表现形式就是docker0这个网络接口。容器默认都是通过docker0这个接口进行通信。也可以通过docker0去和本机的以太网接口连接&#xff0c;这样容器内部才能访问互联网。 # 查看docker0网络&#xff0c;在默认环境中&#xff0c;一个名为docker0的linux b…

Go语言的TCP和HTTP网络服务基础

目录 【TCP Socket 编程模型】 Socket读操作 【HTTP网络服务】 HTTP客户端 HTTP服务端 TCP/IP 网络模型实现了两种传输层协议&#xff1a;TCP 和 UDP&#xff0c;其中TCP 是面向连接的流协议&#xff0c;为通信的两端提供稳定可靠的数据传输服务&#xff1b;UDP 提供了一种…

NodeJSMongodbMVC管理开发⑨

文章目录 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c;请点三连一波&#xff0c;蟹蟹支持&#x1f618;前言MVC思想开发 服务器代码演示 M层 Services 或 Model V层 Views C层 Controllers总结 ✨文章有误请指正&#xff0c;如果觉得对你有用&#xff0c…

C语言笔记之结构体总结

C语言笔记之结构体总结 code review! 文章目录 C语言笔记之结构体总结一.介绍二.3种结构体类型变量说明1. 先定义结构&#xff0c;再定义结构变量2. 定义结构体类型的同时说明变量3. 直接说明结构变量(匿名结构体) 四.结构体成员表示方法五.结构体指针做参数六.结构体初始化1…