java多线程编程学习chapter3


线程是操作系统中独立的个体,但是这些个体不经过特殊处理就不能成为一个整体,线程间的通信就是成为整体的必用方案之一
线程之间的通信
使用wait/notify实现线程间的通信
生产者/消费者模式的实现
方法join的使用
ThreadLocal类的使用

不适用等待通知机制实现线程中断
参照代码:SimpleThread\src\com\nineclient\call\chapter3\twothread\TransData.java
弊端是线程B不断的通过轮询机制来检测某一个小条件,这样会浪费CPU资源,如果轮询时间段,更浪费CPU资源,如果时间间隔大,可能取不到要得到的数据

等待通知机制
方法wait()的作用就是使当前执行代码的线程进行等待,是Object类的方法,该方法用来将当前线程置入"预执行队列",并在wait的代码处停止执行,直到接到通知或被中断,调用wait之前,线程必须获得对象锁,即只能在同步方法或同步块中调用wait方法,执行wait方法后,当前线程释放锁。wait返回前,线程和其他线程竞争重新获得锁
方法notify也要在同步方法或同步快中调用。执行notify方法之后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获取对象锁,需要等到notify方法的线程将程序执行完。
如果没有获得对象锁,调用了wait方法会抛出InterruptedException
参照代码:SimpleThread\src\com\nineclient\call\chapter3\twothread\Test11.java
SimpleThread\src\com\nineclient\call\chapter3\twothread\Test12.java
SimpleThread\src\com\nineclient\call\chapter3\twothread\Test13.java
notify执行后,并不会立刻释放锁,而是等synchronized代码块中代码执行完
参照代码:SimpleThread\src\com\nineclient\call\chapter3\twothread\TransDataThread.java
进入runnable状态大体分为5种情况
1.调用sleep方法后,经过的时间超过了制定的休眠时间
2.线程调用的阻塞IO已经返回,阻塞方法执行完毕
3.线程成功的获得了试图同步的监视器
4.线程正在等待某个通知,其他线程发出了通知
5.处于挂起状态的线程调用了resume恢复方法
进入Bolcked状态
1.线程调用sleep方法,主动放弃占用的处理器资源
2.线程调用了阻塞式IO,方法返回前,该线程被阻塞
3.线程试图获得一个同步监视器,但该同步监视器正在被其他线程拥有
4.线程等待某个通知
5.程序调用了suspend方法将该程序挂起,此方法容易导致死锁,尽量避免使用该方法
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列

wait方法释放锁,sleep方法不释放锁
参照代码:SimpleThread\src\com\nineclient\call\chapter3\waitandnotify\WaitReleaseLock.java
notify被执行后
参照代码:SimpleThread\src\com\nineclient\call\chapter3\waitandnotify\NotifyHoldLock.java
当interrupt方法遇到wait方法,当线程wait时,调用线程对象的interrupt方法会出现异常
参照代码:SimpleThread\src\com\nineclient\call\chapter3\waitandnotify\WaitInterruptException.java

结论:
执行完同步代码块,就会释放对象的锁
在执行同步代码块的过程中,遇到异常而导致线程终止,锁也会释放
在执行同步代码块的过程中,执行锁所属对象的wait方法,这个线程会释放对象的锁,而此线程会进入线程池进行等待被唤醒

notify只能唤醒一个线程
参照代码:SimpleThread\src\com\nineclient\call\chapter3\waitandnotify\NotifyOneThread.java

wait(long)带一个参数的wait(long)方法功能是在等待某一个时间内是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒
参照代码:SimpleThread\src\com\nineclient\call\chapter3\notify\WaitLong.java

通知过早,如果B线程已经先通知了,那么A线程就不用执行了
参照代码:SimpleThread\src\com\nineclient\call\chapter3\notify\NotifyEarly.java

等待wait的条件发生变化
参照代码:SimpleThread\src\com\nineclient\call\chapter3\notify\WaitContionChange.java

生产者消费者模式
一个生产者一个消费者,一个值
生产者是有值的时候,等待,没值的时候生产,生产完了,唤醒
消费者是没值的时候,等待,有值的时候消费,消费完了,唤醒
参照代码:SimpleThread\src\com\nineclient\call\chapter3\notify\PCmodel.java

多生产与多消费:操作值-假死
当全部线程都进入WAITING状态的时候,则程序就不再执行业务功能了,整个项目呈现停止状态
假死出现是因为唤醒了同类
参照代码:SimpleThread\src\com\nineclient\call\chapter3\notifyall\PCmodel.java

操作值栈,一个生产者,一个消费者,值栈中有一个值
参照代码:SimpleThread\src\com\nineclient\call\chapter3\mystack\MyStackTest.java
一个生产者,和多个消费者
注意,要用while替换if,要notifyAll替换notify
多生产者,多消费者
参照代码:SimpleThread\src\com\nineclient\call\chapter3\mystack\MyStackTest1.java

管道流可以在不同线程间直接传送数据,一个线程发送给数据到输出管道,一个线程从输入管道读取数据
PipedInputStream 和 PipedOutputStream
PipedReader 和 PipedWriter
使用inputStream.connect(outStream)或者outputStream.connect(inputStream)将两个stream连接,这样才可以将数据进行输出和输入
参照代码:和字节流一样

通过管道进行线程间的通信:字节流
参照代码:SimpleThread\src\com\nineclient\call\chapter3\piped\Run1.java

管道进行线程间的通信:字符流
参照代码:SimpleThread\src\com\nineclient\call\chapter3\piped\Run2.java

等待通知交叉备份
参照代码:SimpleThread\src\com\nineclient\call\chapter3\piped\Run3.java

方法join的使用
如果主线程想等待子线程执行完成之后在结束,比如子线程处理一个数据,主线程要取这个数据的值,就要用到join方法了。方法join的作用是等待线程对象销毁

方法join的作用是使所属对象的线程对象x正常执行run方法中的任务,而使当前线程z进行无限期的阻塞,等待x线程销毁后在继续执行线程z后面的代码
参照代码:SimpleThread\src\com\nineclient\call\chapter3\join\Run1.java

在join过程中,如果当前对象被中断,则当前线程出现异常,没有被中断的线程正常运行
参照代码:SimpleThread\src\com\nineclient\call\chapter3\join\Run2.java

方法join(long)设定等待的参数,只等这么长时间,没有结束,就继续执行
参照代码:

方法join(long) 和 sleep(long) 的区别
join方法释放锁,sleep不释放锁
//参照代码:
//参照代码:

join方法后面的代码提前运行
参照代码:join方法也是要抢占锁的,内部实现是调用wait方法

方法join和synchronized的区别
join的内部使用了wait方法进行等待,而synchronized关键字使用的是,对象监视器

类ThreadLocal使用
变量值的共享可以使用public static 变量的形式,所有的线程都使用同一个public static变量,
每一个线程都有自己的共享变量,使用ThreadLocal。
ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocl类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有变量。
参照代码:SimpleThread\src\com\nineclient\call\chapter3\threadlocal\Test1.java

类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程的值是可以放入ThreadLocal类进行保存的
验证线程变量的隔离性
每个线程都向ThreadLocalset值,但每个线程都还能取出自己的值
参照代码:SimpleThread\src\com\nineclient\call\chapter3\threadlocal\Run1.java
参照代码:SimpleThread\src\com\nineclient\call\chapter3\threadlocal\Run2.java

继承ThreadLocal,初始化默认值,即使设置了默认值,不同的线程仍然只能获得自己的值
参照代码:SimpleThread\src\com\nineclient\call\chapter3\threadlocal\Run3.java

值继承,子线程可以获得父线程的值InheritableThreadLocal的使用
参照代码:SimpleThread\src\com\nineclient\call\chapter3\threadlocal\Run4.java

继承来的值可以进行修改
参照代码:SimpleThread\src\com\nineclient\call\chapter3\threadlocal\Run4.java

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值