【Java多线程】(四)线程间通信

1.等待/通知机制

wait和notify都是object类的方法。

wait()是线程停止运行,notify()使停止的线程继续运行。

在调用wait和notify时,必须获得对象级锁,因此必须在同步方法或者同步代码块中执行

wait:释放的对象锁-->该锁被其他线程获取,-->获取该锁的线程调用notify并执行完毕释放对象锁-->原来调用wait方法的对象重新获得对象锁-->继续执行

示例代码:

MyThread1.java

package zzzztrhead;

public class MyThread1 extends Thread {
	private Object lock;

	public MyThread1(Object lock) {
		super();
		this.lock = lock;

	}

	@Override
	public void run() {
		synchronized (lock) {

			try {
				System.out.println("开始wait");
				lock.wait();
				System.out.println("结束wait");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}

}
lock.wait();
				System.out.println("结束wait");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}

}

MyThread2.java:

package zzzztrhead;

public class MyThread2 extends Thread {
	private Object lock;

	public MyThread2(Object lock) {
		super();
		this.lock = lock;

	}

	@Override
	public void run() {
		synchronized (lock) {
			System.out.println("开始notify");
			lock.notify();
			System.out.println("结束notify");

		}
	}

}
lock.notify();
			System.out.println("结束notify");

		}
	}

}

Test:

package zzzztrhead;

public class WaitNotifyTest {
	public static void main(String []args) throws InterruptedException{
		Object lock=new Object();
		MyThread1 t1=new MyThread1(lock);
		t1.start();
		Thread.sleep(3000);//main线程让出cpu
		MyThread2 t2=new MyThread2(lock);
		t2.start();
	}

}

执行结果:

开始wait
开始notify
结束notify
结束wait

由执行结果也可以看出:wait释放对象锁,notify不释放,必须等待执行notify的同步方法或代码块执行完才释放

个人理解的:

wait释放的对象锁-->该锁被其他线程获取,-->获取该锁的线程调用notify并执行完毕释放对象锁-->原来调用wait方法的对象重新获得对象锁-->继续执行

 

2.通过管道进行通信

1.PipedInputStream和PipedOutputStream(字节流)

2.PipedReader和PipedWriter(字符流)

*(outputStream.connect(inputStream);)

3.join方法:

作用:使所属线程对象x正常执行run方法中的任务,使当前线程无线阻塞,等待线程x销毁后再继续执行线程z后面的代码。

在内部使用wait方法进行等待,

源码:

    public final void join() throws InterruptedException {
        join(0);
    }
 public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);//使调用join方法的线程等待
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

还有一点: 

  t1.wait();  //  不是使t1线程等待,而是当前执行wait的线程等待 

4.ThreadLocal的使用

每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。

ThreadLocal源码解析:https://www.cnblogs.com/dennyzhangdd/p/7978455.html#_label0_0

操作一个内部类对象ThreadLocalMap,key=当前线程,value=线程局部变量。数据结构以及get,扩容等等类似于hashmap,set解决冲突用的开放定址法。

InheritableThreadLocal可以让子线程从父线程中取得值。(在线程初始化时,将赋值过去,可通过重写childeVlue方法来修改子线程继承自父线程的值)

你可能感兴趣的:(Java)