【Java】详解多线程同步的三种方式

🌺个人主页:Dawn黎明开始

🎀系列专栏:Java
每日一句:等风来,不如追风去

📢欢迎大家:关注🔍+点赞👍+评论📝+收藏⭐️


 


 

文章目录

一.🔐线程安全

1.1🔓案例引入

1.1.1🔑问题

1.1.2🔑实例操作

1.2🔓说明

二.🔐同步代码块

2.1🔓语法格式

2.2🔓全局锁

🚩实例练习1

2.3🔓任意锁

🚩实例练习2

2.4🔓局部锁

🚩实例练习3

2.5🔓this对象作为锁

🚩实例练习4

2.6🔓注意

三.🔐同步方法

3.1🔓语法格式

3.2🔓实例练习

3.3🔓思考

四.🔐同步锁(重入锁)

4.1🔓语法格式

4.2🔓实例练习


一.🔐线程安全

1.1🔓案例引入

1.1.1🔑问题

       电影院上映一部电影,共有三个窗口,请你设计一个模拟电影院卖票的程序。

1.1.2🔑实例操作

代码如下👇🏻 

package Process3;public class SellTicket implements Runnable {private  int tickets = 20;//总票数private int ticketId = 1;//票号@Overridepublic void run() {while (tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++}}}
package Process3;public class SellTicketDemo {public static void main(String[] args) {// 创建资源对象SellTicket st = new SellTicket();// 创建三个线程对象Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");// 启动线程t1.start();t2.start();t3.start();}
}

运行结果👇🏻

总结:该方法不可以,有重票和漏票和多票问题。 

1.2🔓说明

           线程安全问题其实就是由多个线程同时处理共享资源所导致的。要想解决线程安全问题,必须得保证处理共享资源的代码在任意时刻只能有一个线程访问。为此,Java中提供了线程同步机制。

二.🔐同步代码块

2.1🔓语法格式

原理

      (1).当线程执行同步代码块时,首先会检查lock锁对象的标志位。

      (2).默认情况下标志位为1,此时线程会执行Synchronized同步代码块,同时将锁对象的标志位置为0。

      (3).当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后。

      (4).锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代码,这样循环往复,直到共享资源被处理完为止。

 同步代码块:

 * synchronized(对象){

 * 需要同步的代码;

 * }

 *

 * (1).对象是什么呢?

 * 我们可以随便创建一个对象试试。

 * (2).需要同步的代码是哪些呢?

 * 把多条语句操作共享数据的代码的部分给包起来

 *

 * 注意

 * (1).同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。

 * (2).多个线程必须是同一把锁。

2.2🔓全局锁

注:以下四种方法的测试类都一样(只有2.2写了测试类,其余省略了)

🚩实例练习1

代码如下👇🏻 

package Sell;public class SellTicket implements Runnable {private   int tickets = 20;//总票数private int ticketId = 1;//票号Object o =new Object();//全局锁@Overridepublic void run() {while (tickets>0) {synchronized (o) {if(tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++}}}}}
package Sell;public class SellTicketDemo1 {public static void main(String[] args) {// 创建资源对象SellTicket1 st = new SellTicket1();// 创建三个线程对象Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");// 启动线程t1.start();t2.start();t3.start();}
}

运行结果👇🏻

2.3🔓任意锁

🚩实例练习2

代码如下👇🏻 

package Sell;public class SellTicket1 implements Runnable {private int tickets = 20;//总票数private int ticketId = 1;//票号Demo lock =new Demo();//任意锁@Overridepublic void run() {while (tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock) {//  为什么有if判断?//  如果没有if,t1执行结束,tickets=0,这样t2,t3再执行同步代码块之后,票会变成负数,票会多卖if(tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++  // 多卖21,22}}}}}
class Demo{//任意类
}

运行结果👇🏻

2.4🔓局部锁

🚩实例练习3

代码如下👇🏻 

package Sell;public class SellTicket1 implements Runnable {private int tickets = 20;//总票数private int ticketId = 1;//票号@Overridepublic void run() {Object lock =new Object();//局部锁锁不住while (tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock) {//  为什么有if判断?//  如果没有if,t1执行结束,tickets=0,这样t2,t3再执行同步代码块之后,票会变成负数,票会多卖if(tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++  // 多卖21,22}}}}}

运行结果👇🏻

总结:该方法不可以,有重票和漏票问题。

2.5🔓this对象作为锁

🚩实例练习4

代码如下👇🏻 

package Sell;public class SellTicket1 implements Runnable {private int tickets = 20;//总票数private int ticketId = 1;//票号@Overridepublic void run() {while (tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}synchronized (this) {//  为什么有if判断?//  如果没有if,t1执行结束,tickets=0,这样t2,t3再执行同步代码块之后,票会变成负数,票会多卖if(tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++  // 多卖21,22}}}}}

运行结果👇🏻

说明:项目开发中一般使用this关键字作为锁对象。

2.6🔓注意

三.🔐同步方法

3.1🔓语法格式

3.2🔓实例练习

 代码如下👇🏻 

package Sell;public class SellTicket1 implements Runnable {private int tickets = 20;//总票数private int ticketId = 1;//票号@Overridepublic void run() {while (tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}Selltickets ();}}//方法抽取://同步方法public synchronized void Selltickets () {if(tickets>0) {System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++  // 多卖21,22}}}
package Sell;public class SellTicketDemo1 {public static void main(String[] args) {// 创建资源对象SellTicket1 st = new SellTicket1();// 创建三个线程对象Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");// 启动线程t1.start();t2.start();t3.start();}
}

运行结果👇🏻

3.3🔓思考

     (1).同步方法的格式及锁对象问题?

           把同步关键字加在方法上

     (2).同步代码块的锁对象是谁?

           任意全局对象   一般使用this作为锁对象

     (3).同步方法的锁是谁?

           this,它是隐含的

四.🔐同步锁(重入锁)

4.1🔓语法格式

 Lock:

 * void lock(): 获取锁。

 * void unlock():释放锁。  

 * ReentrantLock是Lock的实现类.

4.2🔓实例练习

代码如下👇🏻 

package Sell;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class SellTicket1 implements Runnable {private int tickets = 20;//总票数private int ticketId = 1;//票号Lock lock =new ReentrantLock();//同步锁(重入锁)@Overridepublic void run() {while (tickets>0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}lock.lock();//上锁if(tickets>0) {System.out.println(Thread.currentThread().getName() + "正在出售第"+ ticketId + "张票");tickets--; //剩余票数--ticketId++; //票号++  }lock.unlock();//开锁}}}
package Sell;public class SellTicketDemo1 {public static void main(String[] args) {// 创建资源对象SellTicket1 st = new SellTicket1();// 创建三个线程对象Thread t1 = new Thread(st, "窗口1");Thread t2 = new Thread(st, "窗口2");Thread t3 = new Thread(st, "窗口3");// 启动线程t1.start();t2.start();t3.start();}
}

运行结果👇🏻


​🌺建议大家亲自动手操作,学编程,多实践练习是提升编程技能的必经之路。

🌺欢迎大家在评论区进行讨论和指正!

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

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

相关文章

总结1057

考研倒计38天 极限冲刺day1 今日共计学习13h33m,为了能走出备考的低谷阶段,来一场与自我的较量。在尽可能保证效率的情况下,玩命干。考研这件事,从来不是因为看到了希望才去努力,而是玩命努力后才看到希望。

重生之我是一名程序员 31

大家晚上好!前面给大家分享了指针与数组的知识,所以今天要给大家分享的知识是——指针数组 相信大家在这里都会有疑问,指针数组是指针还是数组? 在这我们可以类⽐⼀下其他类型的数组,比如整型数组是存放整型的数组&am…

Postman的Cookie鉴权

近期在复习Postman的基础知识,在小破站上跟着百里老师系统复习了一遍,也做了一些笔记,希望可以给大家一点点启发。 一)什么是Cookie 定义:存储在客户端的一小段文本信息,格式为键值对的形式. 二&#xff09…

单片机实验(一)

前言 实验一:用单片机控制多只数码管(屏)分别左、右滚动显示自己完整的学号; 实验二:用单片机控制LED1616点阵交替正序、逆序显示自己的中文姓名。 参考链接: LED数码管的静态显示与动态显示(KeilProteus&#xff0…

【C语言 | 数组】C语言数组详解(经典,超详细)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

【LeetCode:307. 区域和检索 - 数组可修改 | 树状数组 or 线段树】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

保姆级教程之SABO-VMD-CNN-SVM的分类诊断,特征可视化

今天出一期基于SABO-VMD-CNN-SVM的分类诊断。 依旧是采用经典的西储大学轴承数据。基本流程如下: 首先是以最小包络熵为适应度函数,采用SABO优化VMD的两个参数。其次对每种状态的数据进行特征向量的求取,并为每组数据打上标签。然后将数据送入…

VN5620以太网测试——DoIP配置

文章目录 前言一、DoIP简介二、Vector Hardware Configuration三、Diagnostics/ISO TP Configuration四、Diagnostic Console五、添加Ethernet Packet Builder前言 CANoe(CAN open environment)VN5620 :是一个紧凑而强大的接口,用于以太网网络的分析、仿真、测试和验证。 V…

Go 理解零值

在 Go 语言中,零值(Zero Value)是指在声明变量但没有显式赋值的情况下,变量会被自动赋予一个默认值。这个默认值取决于变量的类型,不同类型的变量会有不同的零值。零值是 Go 语言中的一个重要概念,因为它确…

低代码编辑平台后台实现

背景 之前做过一个前端低代码编辑平台,可以实现简单的移动端页面组件拖拽编辑: https://github.com/li-car-fei/react-visual-design 最近基于C的oatpp框架实现了一下后台。使用oatpp框架做web后台开发时,发现按照官方的示例使用的话&#…

设计模式(4)-行为型模式

行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间…

基于模拟退火算法的TSP问题建模求解(Python)

基于模拟退火算法的TSP问题建模求解(Python) 一、模拟退火算法(Simulated Annealing Algorithm,SAA)工程背景模拟退火算法用于优化问题求解原理 二、旅行商问题(Travelling salesman problem,TS…