目录

课上

synchronized有三种方式来加锁,分别是

同步代码块中可以用的结构

使用synchronized解决线程同步问题的两种方式

同步方法:

同步代码块:

死锁

在Java中死锁产生的四个必要条件

线程重入

JDK1.6以后锁升级:

Object类对多线程的支持

线程间的通信

方法的总结:

面试题:sleep和wait的区别

线程的退出

线程的常用方法:

懒汉式的最终版

课下

案例1:生产者与消费者模型

例题 2:吃包子,包子铺做包子例题

案例3:自己瞎写的

总结


课上

synchronized 多线程并发编程

重量级锁。JDK1.6对synchronized进行了优化。

JDK1.6为了减少获得锁和释放锁带来的性能消耗,引入的偏向锁和轻量级锁。

synchronized有三种方式来加锁,分别是

  1. 修饰实例方法,作用于当前实例加锁,进入同步代码之前要获得当前实例的锁
  2. 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得的当前类对象的锁。
  3. 代码块、同步代码块。指定加锁对象,对给定的对象加锁,进入同步代码块之前,要获得给定对象的锁。

·实例方法:调用该方法的实例

·静态方法:类对象

·this:代表该方法的实例对象

·类对象:类对象

同步代码块中可以用的结构

1)创建一个对象

2)类对象

3)当前实例this

括号里的也可以叫同步监视器

操作共享数据的代码

共享数据:多个县城共同操作的变量,都可以充当锁

当使用同步方法时,synchronized锁的东西是this,this代表当前类的对象,也就是方法的调用者(默认的)

使用synchronized解决线程同步问题的两种方式

同步方法:

  1. 同步方法依然会涉及到同步锁对象,只是不需要我们写出来
  2. 非静态的同步方法,同步锁就是this

静态的同步方法,同步监视器就是类本身

同步代码块:

  1. 首先要选好同步监视器(同步锁),选好用哪一个对象,推荐使用类对象,第三方对象,this。
  2. 在实现接口创建的线程类中,同步代码块是不可以用this来充当同步锁的。推荐使用类对象。

同步的方式,解决线程安全的问题。

操作同步代码时,只有一个线程能够参与,其他线程等待。

相当于一个单线程的过程,效率低。

synchronized只针对于当前JVM虚拟机可以解决线程安全问题。

synchronized弊端:不能跨JVM解决问题。


死锁

死锁是这样一种情形:多个县城同时被阻塞,他们中的一个或者全部都在等待某个资源的释放右玉县城无限期的阻塞,程序就不可能正常终止。

在Java中死锁产生的四个必要条件

  1. 互斥使用:当资源被一个线程使用(占用),别的线程不能使用
  2. 不可抢占:资源的请求者不能强制从占有者中抢夺资源,资源只能从占有者手动释放
  3. 请求和保持
  4. 循环等待:通常会存在一个等待的队列。例如P1占有了P2的资源,P2占有了P3的资源,P3占有了P1的资源。形成了一个等待环路。

线程重入

任意线程在拿到锁之后,再次获取该锁不会被该锁阻碍

线程不会被自己锁死,这就叫线程的重入

synchronized又叫可重入锁

JDK1.6以后锁升级:

  1. 无锁:不加锁
  2. 偏向锁:不锁锁,当只有一个线程争夺时,偏向某一个线程,这个线程不加锁
  3. 轻量级锁:少量线程来了之后,先尝试自旋(尝试自己能不能解决问题),不挂起线程。
  4. 重量级锁:排队挂起(暂停)线程(synchronized是重量级锁)

挂起线程和恢复线程需要转入内核态中完成这些操作,会给系统的并发性带来很大的压力。

在许多应用上共享数据的锁定状态,一般情况下智慧持续很短的时间,为了这段时间去挂起和恢复并不值得。

我们可以让后面的线程等待一下,不要放弃处理器的执行时间。

锁是为了让线程等待,我们只需要让线程之星一个循环,自旋。【自旋锁】

Object类对多线程的支持

wait()

wait(loong timeout):当前线程进入 等待状态

notify():唤醒正在等待的下一个线程

notifyAll():唤醒正在等待的所有线程

不是线程类提供的方法

这两种方法的使用前提,必须要有锁,要有线程同步

线程间的通信

比如两条线程共同运行。线程A如果先走,线程B就要等待,等到线程A走完,唤醒线程B,线程B再走。

方法的总结:

1.Thread的两个静态方法:

sleep方法释放CPU资源,但是不会释放锁

yield方法释放CPU的执行权,保留了CPU的执行资格,不常用

2.join方法,出让了执行权,join就加入进来

3.wait方法:释放CPU资源,释放锁

Notify:唤醒等待中的线程

notifyAll:唤醒等待中的所有线程

面试题:sleep和wait的区别

sleep 一般用于当前线程休眠,或者轮循暂停操作,wait 则多用于多线程之间的通信。 sleep 是Thread 类的静态本地方法,wait 则是Object 类的本地方法。

  1. 出处:sleep是Thread;wait是Object
  2. 对于锁的控制

线程的退出

(1)使用退出标志,来让线程正常退出,run方法结束后线程终止

不要使用stop方法

(2)interrupt方法:终端线程

调用interrupt方法会抛出InterruptdeException异常。捕获后再做停止线程的逻辑即可。

如果线程while(true)

线程的常用方法:

Thread类中的方法

start方法:启动当前线程,执行run方法

run方法

currentThread方法:静态方法,获取当前正在执行的线程

getId():返回次线程的唯一标识

setName():设置当前线程的name

getName():获取当前线程的name

getPriority():获取当前线程的优先级

setPriority(int):设置当前线程的优先级

getState():获取当前线程的生命周期

interrupt():中断线程的执行

interrupted():查看当前线程是否中断

懒汉式的最终版

推荐使用内部类,枚举的方式解决问题,因为枚举天生就是单例的,天生构造器私有化。

枚举天生就是用来做单例模式。

课下

案例1:生产者与消费者模型

这个模型大概思路呢就是:

生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

简单来说:有两条线程,一条线程生产产品,另一条线程消费产品:

比如:工厂生产了100台电脑,生产完毕,唤醒等待的消费者,工厂等待。消费者被唤醒,100台电脑被卖出去后,等待。再唤醒工厂继续生产,反反复复

class Factory implements Runnable {@Overridepublic void run() {synchronized (Ch02.OBJ){//加锁while(true){//进入循环// 生产电脑System.out.println("工厂生产电脑,已经生产了:" + Ch02.count ++ + "台!");if(Ch02.count >= 100) {try {Ch02.OBJ.wait();//等待进程} catch (InterruptedException e) {e.printStackTrace();}Ch02.OBJ.notifyAll();//唤醒进程}}}}
}
class Consumer implements Runnable {@Overridepublic void run() {synchronized (Ch02.OBJ){//加锁while(true){if(Ch02.count >= 0){// 消费电脑System.out.println("消费者消费了1台电脑,剩余:" + Ch02.count-- + "台!");}if(Ch02.count <= 0){try {Ch02.OBJ.wait();} catch (InterruptedException e) {e.printStackTrace();}Ch02.OBJ.notifyAll();}}}}
}
public class Ch02 {public static final Object OBJ = new Object();public static int count = 0;public static void main(String[] args) {Thread t1 = new Thread(new Factory());Thread t2 = new Thread(new Consumer());t1.start();//启动线程t2.start();//↑}
}

输出结果:

例题 2:吃包子,包子铺做包子例题

class BaoZi{boolean flag=false;//包子是否存在 true有包子 消费 flase 没包子 生产String pier;String xian;public BaoZi() {}public BaoZi(String pier, String xian) {this.pier = pier;this.xian = xian;}//生产包子public synchronized void productBaoZi(){if(flag==true){//有包子try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//生产System.out.println("包子铺开始做包子");System.out.println("包子作好了"+this.pier+this.xian);flag=true;notify();//通知对方开始吃包子}//消费包子public synchronized void eatBaozi(){if(!flag){//包子没作做好try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("吃货正在吃包子"+this.pier+this.xian);System.out.println("====================");flag=false;notify();//通知对方做包子}
}
public class BaoZiPuTest {public static void main(String[] args) {BaoZi bz = new BaoZi("薄皮", "牛肉");//生产线程new Thread(new Runnable() {@Overridepublic void run() {while (true) {//生产包子需要时间try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}bz.productBaoZi();}}}).start();//消费线程new Thread(new Runnable() {@Overridepublic void run() {while (true) {bz.eatBaozi();}}}).start();}
}

输出结果:

案例3:自己瞎写的

public class J8031 {public static void main(String[] args) {Food food = new Food();Producter producter = new Producter(food);Customer customer = new Customer(food);Thread t1 = new Thread(producter);Thread t2 = new Thread(customer);t1.start();t2.start();}
}class Customer implements Runnable{private Food food;public Customer(Food food){this.food = food;}@Overridepublic void run() {for (int i = 0; i <20; i++) {food.get();}}
}
//生产者
class Producter implements Runnable{private Food food;public Producter(Food food){this.food = food;}@Overridepublic void run() {for (int i = 0; i <20 ; i++) {if(i%2==0){food.set("鲤鱼焙面","皇帝老子不及吾");}else {food.set("吃了咸菜滚豆腐","延津做法");}}}
}class Food{private String name;private String desc;//生产产品public void set(String name,String desc){this.setName(name);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}this.setDesc(desc);}//消费产品public void get(){try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(this.getName()+"->"+this.getDesc());}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}@Overridepublic String toString() {return "Foot{" +"name='" + name + '\'' +", desc='" + desc + '\'' +'}';}public Food(String name, String desc) {this.name = name;this.desc = desc;}public Food(){}
}

输出结果:

吃了咸菜滚豆腐->皇帝老子不及吾
鲤鱼焙面->延津做法
吃了咸菜滚豆腐->皇帝老子不及吾
鲤鱼焙面->延津做法
吃了咸菜滚豆腐->皇帝老子不及吾
鲤鱼焙面->延津做法
吃了咸菜滚豆腐->皇帝老子不及吾
鲤鱼焙面->延津做法

。。。

总结

今天学习了锁的应用,这一部分算是线程知识的分界点了,感觉听的一知半解,生产者、消费者题目也只是知道方法,并不会写,还得加强。

2022-8-03 第七小组 黄均睿 学习日记 (day27)线程2相关推荐

  1. 2022-07-08 第七小组 闫馨月 学习笔记

    单丝不成线,独木不成林,只有携手并进,才能共赢.强者抱团,渡人渡己,人与人之间最好的关系就是坦诚相待,彼此成就,合作共赢! 在2022年7月8日有幸参与盛世吉软组织为期一天的团队素质拓展训练,除了身体 ...

  2. 2022-07-10 第七小组 闫馨月 学习笔记

    CSS CSS:层叠样式表,相当于整个网页的美化. 如何显示html元素? 样式通常存储在样式表中(先定义样式表),再把样式表添加到html元素中 定义CSS样式的方式: 1.行内样式(内联样式) 2 ...

  3. 2022-07-13 第七小组 闫馨月 学习笔记

    目录 JAVA JAVA特点: 操作系统基本命令: 计算机的一些设置 二进制 存储单位: 二进制的加减法计算 JAVA环境搭建 安装JAVA 自己配置环境变量 java入门程序-HelloWorld ...

  4. 今日创见|2022创业者必读的七本好书推荐

    如今的企业经济都是关于速度.增长和保持不破产.随着消费者行为.数字化技术和全球化发生翻天覆地的变化,不断创新和挑战现状比以往任何时候都更为重要.我们做了一份企业家"必读"清单,其中 ...

  5. Dapr中国社区活动之 分布式运行时开发者日 (2022.09.03)

    自2019年10月首次发布以来,Dapr(Distributed Application Runtime,分布式应用运行时)因其"更稳定"."更可靠".&quo ...

  6. 2022年03月-电子学会青少年等级考试C语言(一级)真题与解析

    微信扫码关注公众号获取更多资讯 2022年03月软件编程(C语言)等级考试(一级) 分数:100   题数:5 时间限制:1000 ms   内存限制:65536 kB 1.双精度浮点数的输入输出 [ ...

  7. 【HZHE004】黄子涵学习Echarts

    概念篇 数据集 数据集(dataset)是专门用来管理数据的组件.虽然每个系列都可以在 series.data 中设置数据,但是从 ECharts4 支持 数据集 开始,更推荐使用 数据集 来管理数据 ...

  8. ScalersTalk 机器学习小组第 21 周学习笔记(深度学习-10)

    ScalersTalk 机器学习小组第 21 周学习笔记(深度学习-10) Scalers点评:机器学习小组是成长会的内部小组,这是成长会机器学习小组第21周学习笔记,也是深度学习第10次的复盘笔记 ...

  9. 同个局域网内的A,B两个电脑主机,A能PING通B电脑,B无法PING通A 电脑,双方均能学习到对方ARP地址

    A电脑:10.1.118.150/24 B电脑:10.1.118.189/24 现象:同个局域网内的A,B两个电脑主机,A能PING通B电脑,B无法PING通A 电脑,双方均能学习到对方ARP地址 ( ...

  10. 【HZHE003】黄子涵学习Echarts

    概念篇 ECharts 中的样式简介 本文主要是大略概述,用哪些方法,可以在 Apache EChartsTM 中设置样式,改变图形元素或者文字的颜色.明暗.大小等. 本文介绍这几种方式,他们的功能范 ...

最新文章

  1. h5做的app和原生app的区别
  2. 高可用集群技术之RHCS应用详解(一)
  3. JQuery操作CheckBox和Radio
  4. Codeforces Round #470 (rated, Div. 2 C. Producing Snow(思维)
  5. Linux Kernel 3.8.8/3.4.41/3.0.74 发布
  6. legacy bios与uefi两种模式安装windows8操作系统的方法
  7. 数据结构与算法 / 堆结构
  8. 程序设计中的驼峰原则
  9. 基于DDD的.NET开发框架 - ABP模块设计
  10. 关键段 互斥量 以及信号量
  11. HTML、 CSS、 JavaScript三者的关系
  12. sql中exec是什么意思_SQL 中为什么经常要加NOLOCK?
  13. python中int input_关于python:如何接受int和float类型的输入?
  14. aes c语言 逆列混合函数,c语言aes列混合和逆列混合的实现(3页)-原创力文档
  15. 新产品、新团队、新技术
  16. MySQL学习笔记2:数据库的基本操作
  17. DB2数据库基本操作
  18. oracle 查询字段去空格,ORACLE 所有表的所有字段去空格方法
  19. 英文论文检索数据库以及英文文献下载
  20. 成功的发行模式(标题 我自己改的 转至 敏思博客)

热门文章

  1. Python实战案例:tornado接口vue客户端的堂食点餐系统(中)
  2. JAVA对接公众号(三、创建自定义菜单)
  3. sqlserver排序规则介绍以及修改
  4. Csdn富文本编辑器中使用Emoji表情包
  5. 洛谷P1007 独木桥
  6. Excel - 字符串处理函数:LEFT, RIGHT, MID, LEN 和 FIND
  7. VIJOS-P1152 肥猫的游戏
  8. AndroidStudio导入Bmob后端云一系列错误
  9. HDU 6638 Snowy Smile 线段树+最大子段和
  10. mysql 错误 1548_mysql报1548错误-Cannot load from mysql.proc. The table is probably corrupted