Java基础第九天:动力节点版本

该文档是:Luo学习Java笔记...

博客连接:https://www.loveuluo.cn

日期:2020-11-10

1. 多线程概念

image-20201110143350710

image-20201110143748821

image-20201110143911167

image-20201110150611128

image-20201110144547157

image-20201110152846166

2. 线程创建

image-20201110161342053

2.1 方式一:继承Thread类

image-20201110161348548

image-20201110154940065

如果使用myThread的run方法的话,就是单纯的再main 主栈里调用了一个方法,等这个方法结束之后才会去调用下边的方法。

而使用start方法等于说是启动了一个分支线程,在JVM中开辟一个新的栈空间。此时run方法就会出现在分支栈的底部,

run方法在分支栈的栈底部,main方法在主栈的栈底部。run和main是平级的。

image-20201110155144393

image-20201110155111425

2.2 run()和start()的区别

run()方法内存图:逐行执行 run方法压栈执行输出0-999,run方法结束弹栈,继续执行输出main方法中的输出0-999

image-20201110160205524

start() 方法内存图:start()方法压栈,执行开辟新的栈空间称为分支栈,start()方法方法结束弹栈,main方法和run方法同时执行输出999(并行)。

image-20201110160735568

2.3 方式二:实现Runnabl接口(建议使用)

使用接口可以实现接口的同时可以继承别的类。(面相接口编程)

image-20201110162719709

image-20201110162111009

image-20201110162044221

采用匿名内部类方式优化代码:

直接new 对象可以自动生成匿名内部类并重写方法。

image-20201110163323530

image-20201110163334203

3. 线程的生命周期

image-20201111095432740

4. 线程的方法

4.1 获取当前线程对象方法,获取线程对象的名字方法,修改线程对象的名字

image-20201110192402723

image-20201110192446079

image-20201110192657981

4.2 睡眠方法

image-20201110194030751

image-20201110193907322

倒计时十秒:

image-20201110194208935

4.3 睡眠方法面试题

因为sleep是个静态方法,和对象没啥关系。(sleep方法的作用是让当前线程陷入睡眠)

静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法

image-20201110194735193

4.4 叫醒一个正在睡眠的线程方法

image-20201110200215198

上边的interrupt方法靠的是抛异常,一但抛异常下图中的try catch 就能抓(catch)住异常,一旦抓住了 try代码就结束了,

执行catch里的代码后整个trycatch就结束了。

image-20201110200312024

4.5 合理的终止一个线程的执行

image-20201111093330660

image-20201111093428511

可以在终止前做数据保护的事,然后再return结束掉,可以防止数据丢失。

image-20201111093417235

5. 线程调度的概念

image-20201111094650050

5.1 有关线程调度的方法

都不是重点,了解即可。

image-20201111095930891

image-20201111100132485

优先级方法:

image-20201111100612252

让位方法:

image-20201111102517902

image-20201111102705165

线程合并方法:

栈直接协调,并不是合并。

image-20201111102935623

6. 线程安全(重点)

6.1 概述

image-20201111150455887

image-20201111150238201

image-20201111150649390

image-20201111150859898

6.2 线程不安全案例

案例一:银行案例

银行账户类(设置get、set方法):

image-20201111164350733

银行账户类中的取款方法(加上sleep后,例如t1线程执行完取钱的方法,接着到sleep时还未执行更新银行账户余额的方法,

t1进入睡眠,此时t2进入进行取钱,但此时账户的余额还未被t1修改,对t2来说银行账户余额还是10000,此时百分百会产生错误):

image-20201111162715154

线程类(两个线程共享一个银行账户):

image-20201111163023090

image-20201111163129073

测试类(设置银行账户名字为act-001,拥有金额10000元,创造两个线程每个线程都同时往相同的账户取5000元):

image-20201111162616936

结果为:image-20201111163207591

错误产生,银行账户余额是一万,每人都取5000,余额还是5000。正确结果应该余额为0才对。

6.3 线程同步机制

锁池并不是一种状态,锁池属于于一种阻塞的状态(阻塞状态中的一员),详情看下图:

image-20201114084301134

image-20201114084211287

6.3.1 synchronized()代码块*

把6.2中不安全案例中的银行账户类中的取钱方法,加上synchronized代码块:

image-20201111165322314

image-20201114085702026

image-20201111165710766

因为这个取款的实例方法是银行账户中的方法,所以如果要调用该方法,需要银行账户对象进行调用,所以这里的this代表了

调用这个取款方法的银行账户对象Account,而Account对象就是这些线程所共享的。

image-20201111170037302

synchronized()中只要是共享对象就行,例如:

银行账户类中new一个obj实例变量

image-20201114091301381

在取款的方法中的synchronized括号中填入obj,也能共享,因为实例变量obj也是共享的,只有一份。

image-20201114092019111

image-20201114091451556

内存图:

image-20201114091617311

在取款的方法中的synchronized括号中填入字符串"abc",也能共享,因为abc在常量池中,只有一份。不过会导致所有的线程都会同步。

image-20201114092414822

括号中传入this和"abc"的区别:

用this的话,t3和 t2/t1的共享对象不是同一个,t3的对象是act2,而t2/t1的对象是act1,所以此时t2和t1会进行排队,而t3不会。

如果使用的是"abc"的话会导致所3个线程都进行排队,浪费了性能。

image-20201114092605365

6.3.2 扩大同步范围

在线程类中使用synchronized代码块包括act的取款方法也可以,传入act,因为act是共享对象所以可以,这里用this不行,

this代表的是线程对象,而每个线程对象之间不共享,这种方式也可以,不过扩大了同步范围,效率更低了。

image-20201114093928725

6.3.3 哪些变量存在线程安全问题*

image-20201114093530372

image-20201114093517535

6.3.4 synchronized出现在实例方法上

image-20201114100533487

image-20201114100602556

默认就是this,没得挑:

image-20201114100549098

6.3.5 集合和String包装类的选择

image-20201114100934216

6.3.6 synchronized 三种写法总结

image-20201114101748460

6.3.7 synchronized 四个例子(面试题)

例子一:一个方法上锁,一个方法不上锁需要等待吗?

image-20201114102457229

image-20201114102522996

image-20201114102507878

例子二:两个方法都上锁需要等待吗?

image-20201114103414734

image-20201114103422139

例子三:创建两个MyClass对象的时候需要等待吗?

image-20201114103457636

image-20201114103504684

例子四:创建两个MyClass对象,使用synchronized锁住静态方法需要等待吗?

image-20201114103607910

image-20201114103616282

6.3.8 死锁

synchronized在开发中最好不要嵌套使用,一不小心就可能导致死锁现象的发生。

image-20201114110041053

image-20201114110050778

image-20201114105548845

6.3.9 在开发中什么时候使用线程安全机制

image-20201114110640617

7. 守护线程

image-20201114143301466

image-20201114143539301

将线程对象设置为守护线程,就算是while(true),当用户线程结束后守护线程还是会自动结束。

image-20201114143729708

8. 定时器

image-20201114144119511

image-20201114151622856

image-20201114151926155

结果:

image-20201114151901220

9. 线程创建的第三种方式

这个方法创建的线程可以获得方法的返回值。

image-20201114153135846

10. wait 和 nofity

image-20201114162555338

image-20201114162426055

10.1 生产者和消费者模式

image-20201114163416693

代码实现(自己代入代码梳理一遍逻辑就能明白):

image-20201115093803998

image-20201115093821839

image-20201115093833532

最后修改:2020 年 11 月 28 日 09 : 53 AM
如果觉得我的文章对你有用,请随意赞赏