【多线程基础】 线程间通信


技术要点:


1,等待/通知机制
1)不使用等待/通知机制实现线程间的通信
2)通知方法执行后,并不立即释放锁。关键字同步可以将任何一个对象作为同步对象来看待,而java的为每个对象都实现了等和和通方法。他们必须在同步同步的对象的临界区内,荣国调用等方法可以使处于临界区的线程进入等待状态,同时释放被同步对象的锁。
通知操作可以唤醒一个因调用了等待操作而处于阻塞状态中的线程。使其进入就绪状态。
被重新唤醒的线程会试图重新获得临界区的控制权,也就是锁,并继续执行临界区内等待之后的代码,如果发出通知操作时,没有处于阻塞状态中的线程,那么该命令会被忽略。
3)等方法可以使用调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒
4)通知()方法可以随机唤醒等待队列中等待同一共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,也就是通知()方法仅通知“一个”线程。
5)notifyAll的()方法可以使所有正在等待队列中等待同一共享资源的“全部”线程从等待状态退出,可以进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,因为这要取决于JVM虚拟机的实现。




6)方法的等待()锁释放与通知()锁不释放
当方法等待()被执行后,锁被自动释放,
但是执行完通知()方法。锁不自动释放。
7)总结3点
执行完同步代码块就会释放对象的锁。
在执行同步代码的过程中,遇到异常而导致线程终止,锁也会被释放。
在执行同步代码块的过程中,执行了锁所属对象的等待方法,这个线程会释放对象锁,而此线程对象会进入线程等待池中,等待被唤醒。
8)只通知一个线程
调用方法通知()一次只能随机通知一个线程进行唤醒。
9)方法等待(长)的使用
带一个参数的等待(长)方法的功能是等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒
10)通知过早
如果通知过早,则会打乱程序正常的运行逻辑。
11)等待等待的条件发生变化
在使用等待/通知模式时,还需要注意另外一种情况,也就是等待等待的条件发生了变化,也容易造成程序逻辑的混乱。
12)生产者/消费者模式实现
等待/通知模式最经典的案例就是“生产者/消费者”模式。但此模式在使用上有几种“变形”,还有一些小的注意事项,但原理都是基于等,通知的。
①一生产与一消费:操作值交替运行
②多生产与多消费:操作值假死假死就是线程进入等待状态。
③多生产与多消费:操作值解决假死很简单,将通知方法改成notifyalll即可,它的原理就是不光通知同类线程,也包括异类。这样就不至于出现假死状态了,程序会一直运行下去。
④一生产与一消费:操作栈:使生产者向堆栈列表对象中放入数据,使消费者从列表堆栈中取出数据。
⑤一生产与多消费 - 操作栈:解决等待条件改变与假死 - 使用notifyAll的
⑥多生产与以消费:操作栈
⑦多生产与多消费:操作栈
13)通过管道进行线程间的通信:字节流
在java的语言中提供了各种各样的输入/输出流流,使我们能够很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程之间直接传送数据。一个线程发送数据到输出管道,另一个线程从输入管道中读取数据。通过使用管道,实现不同线程间的通信,而无须借助于类似临时文件之类的东西

14)通过管道进行线程间通信:字符流


2,方法加入的使用
主线程创建并启动子线程,如果子线程中药进行大量的耗时运算,主线程旺旺将早于子线程结束之前。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要获取这个数据中的值,就要用到join()方法.join 的作用是等待线程对象销毁。
加入与同步的区别是:加入在内部使用wait()的方法进行等待,而同步关键字使用的是:“对象监视器”原理作为同步。
1)join(long)的使用
长是设定的等待的时间加入(2000)和睡眠(2000)的区别:他们运行的效果没有区别,主要区别来自这2个方法对同步的处理上。
睡眠(长)方法不释放锁。
加入(长)方法释放锁


3,类的的ThreadLocal的使用
如果想实现每一个
线程都有自己的共享变量呢?JDK中提供的类的ThreadLocal的正是为了解决这样的问题。
类的ThreadLocal的主要解决的就是每个线程绑定自己的值,可以将ThreadLocal中的类比喻成全局存放数据的盒子,盒子中可
以存储每个线程的私有数据。
方法得到()与null--类的ThreadLocal的解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程
中的值可以放入的ThreadLocal的类中进行保存
变量的隔离性:


4,类的的InheritableThreadLocal的使用
使用类的的InheritableThreadLocal可以在子线程中取得父线程继承下来的值。
1)值继承
使用该类可以让子线程从父线程中取得值。
2)值继承再修改
再继承的同时还可以对值进行进一步的处理注意:如果子线程在取得值得同事,主线程将InheritableTreadLocal中
的值进行更改,那么子线程取到的值还是旧值

猜你喜欢

转载自blog.csdn.net/zhang18330699274/article/details/80932296