首页 > 编程语言 >Java----线程同步

Java----线程同步

时间:2022-10-14 21:13:17浏览次数:55  
标签:同步 Java synchronized 对象 lock ---- 线程 方法

Java----线程同步

案例:卖票

要求:某电影院正在上映国产大片,它有100张票,而该电影院有三个窗口卖票,请设计一个程序模拟该电影院卖票

思路:

① 定义一个类SellTicket来实现Runnable接口,里面定义个变量

② 重写Run()方法,步骤如下:

​ A:若票数大于0,就卖票,并说明是哪个窗口在卖

​ B:卖了票后,票数要减一

​ C:没票了,但肯定还有人来问,所以设置一个死循环

③ 定义一个测试类SellTicketDemo,里面有main()方法,步骤如下:

​ A:创建SellTicket对象

​ B:创建三个Thread对象,将SellTicket对象作为构造方法的参数,并给出名称

​ C:启动线程

卖票出现的问题:

  • 相同票出现了多次
  • 出现了负数的票

问题的原因:

  • 线程的随机性导致

卖票案例数据安全问题的解决

为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)

  • 是否是多线程环境
  • 是否有共享数据
  • 是否有多条语句操作共享数据(切入点)

(如果这三条都是的话,那么肯定出现数据安全性问题)

如何解决多线程数据安全问题?

  • 基本思想:让程序没有安全问题的环境(破坏掉上面三个条件中的一个)

如何实现?

  • 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可
  • 利用java提供的同步代码块解决

同步代码块:

锁住多条语句(线程)操作共享数据,可以使用同步代码块来实现

  • 格式:

​ synchronized(任意对象){

​ 多条语句(线程)操作共享数据的代码

}

  • synchronized(任意对象) 相当于给代码块加锁了,任意对象相当于是锁

同步的好处和弊端

  • 好处:解决了多线程数据安全问题
  • 弊端:当线程很多时,因为每个线程都要去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

同步方法

同步普通方法:

概念:就是把synchronized关键字加到方法上

  • 格式:
    修饰符 synchronized 返回值类型 方法名(方法参数){ }

同步普通方法的锁对象是什么呢?

  • this

同步静态方法:

概念:就是把synchronized关键字加到静态方法上

  • 格式

    修饰符 static synchronized 返回值类型 方法名(方法参数){ }

同步静态方法的锁对象是什么呢?

  • 类名.class

线程安全的类

StringBuffer==StringBuilder

Vector==ArrayList

Hashtable<K,V>==Hashmap<K,V>

以上左边三者均为线程安全的类,区别是:

  • 左边可实现线程安全,右边不行
  • 右边在执行相同操作时,更快,因为它们不执行同步

lock锁

由于我们不理解同步代码块和同步方法在哪里上的锁(synchronized)和在哪里释放的锁,所以JDK5新增一个锁对象Lock

Lock比synchronized方法和语句有更多更广泛的锁定操作

Lock中提供了锁和释放锁的方法:

  • void lock( ) :获得锁
  • void unlock( ) :释放锁

Lock是接口,不能直接实例化,这里采用它的实现类ReentrantLock来实例化:

ReentrantLock的构造方法:

  • ReentrantLock():创建一个ReentrantLock的实例

注意:

  • 一般使用try{

    lock.lock();

    要锁的代码块

    }

    finally{

    lock.unlock();

    }

    这个方法来用lock锁

生产者与消费者模式

一个经典的多线程协作的模式。

  • 生产者线程用于生产数据
  • 消费者线程用于消费数据

为了解耦生产者与消费者之间的关系,通常建立一个共享的数据区域,就像是一个仓库

image-20220830210622748

为了体现生产与消费过程中的等待与唤醒,Java提供了几个方法供我们使用:

Object类的等待与唤醒方法:

方法名 作用
void wait() 将导致当前线程等待(执行一次),直到另一个线程调用该对象的notify()或者notifyAll()方法
void notify() 唤醒正在等待对象监视器的单个线程
void notifyAll() 唤醒正在等待对象监视器的所有线程

生产者与消费者案例

生产者与消费者案例包含的类:

  • 奶箱类(Box):定义一个成员变量,表示第X瓶奶,提供存储牛奶和获取牛奶的炒作
  • 生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶操作
  • 消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶操作
  • 测试类(BoxDemo):main()方法:

​ 步骤:

​ ①创建奶箱对象,共用区域

​ ②创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶操作

​ ③创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶操作

​ ④创建两个线程对象,分别把消费者和生产者对象作为构造参数传递

​ ⑤启动线程

代码实现:

标签:同步,Java,synchronized,对象,lock,----,线程,方法
From: https://www.cnblogs.com/change624/p/16793019.html

相关文章

  • MySQL----语言基础
    MySQL----语言基础语法特点SQL对关键字的大写不敏感SQL语句可以单行或者多行书写,以分号;结束。SQL的注释:--单行注释,--后面一定要加一个空格‘单行注释,可以不用加......
  • PostgreSQL----运行02_insert_data
    ALTERTABLEdepartmentsALTERCONSTRAINTdept_mgr_fkDEFERRABLEINITIALLYDEFERRED;BEGIN;INSERTINTOdepartmentsVALUES(10,'Adminis......
  • PostgreSQL----四个快速脚本
    PostgreSQL----四个快速脚本运行01_create_table.sql创建示例表;--部门信息表CREATETABLEdepartments(department_idINTEGERNOTNULL--部门编......
  • 2022-10-14
    30F:三笔,中枢构筑中  5F:已经2中枢,有背驰迹象,预计30F一笔将结束  计划:1.如果再次冲高,可空30F一笔2.等30F回调一笔,小级别入场做多......
  • 一本通数位DP小结(更新中)
    「一本通5.3例1」AmountofDegrees点击查看代码//先转化为前缀和//从头到尾枚举每一位:这一位的贡献为前面的位都相同,这一位比原来更小,后面的位任意的方案......
  • excel-分类汇总
    先看一张分类汇总的结果图,进而直观的理解分类汇总。解读:意义:按班级分类统计了各科成绩分数的平均值。关键内容:分类字段:班级汇总字段:语文、数学、英语、生物、地理、历史、政......
  • 详解页眉页脚的结构
    关键名词:弄明白这几个关键名词以及设置方法,页眉页脚基本就搞定了。1.节2.首页不同3.奇偶页不同4.链接到前一条页眉解释:1.节word文档默认是一节,通过插入分节符,可以把文档拆分......
  • 查找利器:index+match(函数)
    index与match的组合堪称查找引用中的黄金组合,部分考题中明确指明必须用index和match,因此这两个函数必须掌握。案例图函数解释:index函数:选定一个区域,找到其中的第X行第Y列的......
  • word中删除“空白页”
    想删除空白页,先了解空白页是怎么造成的。对症下药才能药到病除。原因大量空行导致的空白页(简单)分隔符导致的空白页(简单)表格导致的空白页(较难)以上三种原因都是产生空白页的原......
  • excel表格结构化引用
    结构化引用,听起来很神秘的一个词,但是我们几乎每一套题都实实在在的用到它。不需要会书写结构化引用,只要能读懂即可,甚至不读懂也对做题影响不大,但终究是一种磕绊。情景再现公......