java多线程(三)线程间通信
等待,通知机制
* 等待:wait()方法可以使当前执行代码的线程进行等待,在调用wait()方法前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法。在执行wait(0方法之后,当前线程释放锁。在从wait()方法返回前,线程与其他线程竞争重新获取锁。如果没有获取,则会产生异常。
* 通知:notify()方法,只能在同步方法或同步块中调用notify()方法,线程必须获得该对象的对象级别锁。如果在调用notify()方法时没有获取对象级别锁,则会产生异常。当notify()方法被调用并执行完毕之后,处于wait状态的线程才可以获取对象级别锁。
方法wait()锁释放与notify()锁不释放
* 当方法wait()被执行完后,锁被自动释放,但执行完notify()方法,锁却不自动释放。
* 当方法notify()被执行完后,锁不会立即释放,而是要将包含notify()方法在内的所有代码都执行完之后才会释放锁。
notify()方法的特性
* notify()方法只随机唤醒一个处于wait()状态的线程。
wait(long)
* 此方法包含一个时间参数,功能是等待某一时间内是否有线程对锁(因为wait()方法必须在同步方法或者同步代码块中被调用)进行唤醒,如果超过这个时间则自动唤醒。
假死
* “假死的现象其实就是 ”线程进入WAITING等待状态。如果全部线程都进入到WAITING状态,则程序就不执行任何业务了,整个项目呈停止状态。
* 出现假死的主要原因:(在生产——消费模式中),同类连续唤醒同类。
/**
* 生产者
* Created by lx on 2017/4/7.
*/
public class P {
private String lock;
public P(String lock){
this.lock=lock;
}
public void setValue(){
try{
synchronized (lock) {
while (!ValueObject.value.equals("")) {
System.out.println("生产者" + Thread.currentThread().getName() + "WAITING了#");
lock.wait();
}
System.out.println("生产者" + Thread.currentThread().getName() + "RUNNABLE");
String value = System.currentTimeMillis() + "_" + System.nanoTime();
ValueObject.value = value;
lock.notify();
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
/**
* 消费者
* Created by lx on 2017/4/7.
*/
public class C {
private String lock;
public C(String lock){
this.lock=lock;
}
public void getValue(){
try{
synchronized (lock){
while(ValueObject.value.equals("")){
System.out.println("消费者"+Thread.currentThread().getName()+"WAITING#");
lock.wait();
}
System.out.println("消费者"+Thread.currentThread().getName()+"RUNNABLE了");
ValueObject.value="";
lock.notify();
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
/**
* 生产者线程
* Created by lx on 2017/4/7.
*/
public class ThreadP extends Thread {
private P p;
public ThreadP(P p){
this.p=p;
}
@Override
public void run() {
super.run();
while(true){
p.setValue();
}
}
}
/**
* 消费者线程
* Created by lx on 2017/4/7.
*/
public class ThreadC extends Thread {
private C c;
public ThreadC(C c){
this.c=c;
}
@Override
public void run() {
super.run();
while(true){
c.getValue();
}
}
}
/**
* 变量
* Created by lx on 2017/4/7.
*/
public class ValueObject {
public static String value="";
}
/**
* 测试类
* Created by lx on 2017/4/7.
*/
public class Launch {
public static void main(String []args){
String lock = new String("") ;
P p=new P (lock);
C c=new C(lock);
ThreadP[] pThread=new ThreadP[2];
ThreadC[] cThread=new ThreadC[2];
for(int i=0;i<2;i++){
pThread[i]=new ThreadP(p);
cThread[i]=new ThreadC(c);
pThread[i].setName("生产者"+(i+1));
cThread[i].setName("消费者"+(i+1));
pThread[i].start();
cThread[i].start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread[] threadArray=new Thread[Thread.currentThread().getThreadGroup().activeCount()];
Thread.currentThread().getThreadGroup().enumerate(threadArray);
for(int i=0;i<threadArray.length;i++){
System.out.println(threadArray[i].getName()+" "+threadArray[i].getState());
}
}
}
运行的结果为:
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
消费者消费者2WAITING#
生产者生产者2RUNNABLE
生产者生产者2WAITING了#
消费者消费者1RUNNABLE了
消费者消费者1WAITING#
消费者消费者2WAITING#
生产者生产者1RUNNABLE
生产者生产者1WAITING了#
生产者生产者2WAITING了#
main RUNNABLE
Monitor Ctrl-Break RUNNABLE
生产者1 WAITING
消费者1 WAITING
生产者2 WAITING
消费者2 WAITING
假死状态:即最终生产者线程和消费者线程都处于wait状态。
* 解决假死的方法:
将上述类P和类C中的notify()改为notifyAll();
通过管道进行线程间通信:字节流
管道流是一种特殊的流,用于在不同线程之间直接传送数据。一个线程发送数据到输出管道,另一个线程从输入管道中读取数据。通过使用管道,实现不同线程间的通信,而无须借助于类似临时文件之类的问题。
通过管道进行线程间通信:字符流
join方法——同步方法
join方法的使用
在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量耗时的操作,主线程往往会早于子线程而结束。如果在这种情况下,主线程想要等待子线程结束之后再结束,例如,主线程需要子线程中的一个数据,这种情况下我们就需要用到join方法。
方法join()的作用是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无周期的阻塞,等待线程x执行完毕之后再继续执行线程z后边的代码。
方法join与异常
在join过程中,如果当前线程对象被中断(调用interrupt()方法),则当前线程出现异常。而进行join()方法的线程无异常产生。
join(long)的使用
join(long)中的参数是设定等待的时间。
join(long)与sleep(long)方法的区别
方法join(long)的功能在内部是使用wait(long)方法来实现的,所以join(long)方法具有释放锁的特点。
方法sleep(long)不释放锁。
ThreadLocal的使用
ThreadLocal解决的就是每一个线程绑定自己的值。可以将ThreadLocal类比喻为全局存放数据的盒子,盒子中可以存放每一个线程的私有数据。
也可以这么理解:类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同的线程拥有自己的值,不同线程中的值是可以放入ThreadLocal类中进行保存的。
类InheritableThreadLocal的使用
使用类InheritableThreadLocal可以在子线程中取得父线程继承下来的。但如果子线程在取得值的同时,主线程将类InheritableThreadLocal中的值进行更改,那么子线程取得的值还是旧值。