1.等待&通知(wait¬ify)机制:
wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。
notify():方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()仅通知一个线程(notifyAll()可以通知同一个共享资源的全部线程)
ThreadA
public class ThreadA extends Thread {
private Object lock;
public ThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
System.out.println("准备wait");
lock.wait();
System.out.println("wait结束");
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
ThreadB
public class ThreadB extends Thread{
private Object lock;
public ThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("开始执行notify");
lock.notify();
System.out.println("notify执行完毕");
}
}
}
运行类
public class Run {
public static void main(String[] args) {
String lock = new String("lock");
ThreadA threadA = new ThreadA(lock);
threadA.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadB threadB = new ThreadB(lock);
threadB.start();
}
}
这里要注意几点:
1)等待和唤醒一定要在synchronized代码块中执行,否则会报IllegalMonitorStateException
2)线程执行完wait会立刻释放锁,执行完notify并不会立刻释放锁,而是要等执行notify线程走出synchronized代码块才会释放(sleep方法同样不释放锁)
PS:wait(long):带参数的wait方法会在时间内等待唤醒,如果超过时间则自动唤醒
2.通过管道进行线程间通信:字节流
(1)PipeInputStream和PipeOutputStream
(2)PipeReader和PipeWriter
创建ReadData类
public class ReadData {
public void readMethod(PipedInputStream input){
try{
System.out.println("read :");
byte[] byteArray = new byte[20];
int readLenth = input.read(byteArray);
while ( readLenth != -1){
String newData = new String(byteArray,0,readLenth);
System.out.print(newData);
readLenth = input.read(byteArray);
}
System.out.println();
input.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
WriteData类
public class WriteData {
public void writeMethod(PipedOutputStream out){
try{
System.out.println("write:");
for(int i = 0; i < 300; i++){
String outData = "" + (i + 1);
out.write(outData.getBytes());
System.out.print(outData);
}
System.out.println();
out.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
ThreadRead类
public class ThreadRead extends Thread {
private ReadData read;
private PipedInputStream input;
public ThreadRead(ReadData read, PipedInputStream input) {
super();
this.read = read;
this.input = input;
}
@Override
public void run() {
read.readMethod(input);
}
}
ThreadWrite类
public class ThreadWrite extends Thread {
private WriteData write;
private PipedOutputStream out;
public ThreadWrite(WriteData write, PipedOutputStream out) {
super();
this.write = write;
this.out = out;
}
@Override
public void run() {
write.writeMethod(out);
}
}
运行Run类
public class Run {
public static void main(String[] args) {
try{
WriteData writeData = new WriteData();
ReadData readData = new ReadData();
PipedInputStream inputStream = new PipedInputStream();
PipedOutputStream outputStream = new PipedOutputStream();
// pipedInputStream.connect(pipedOutputStream);
outputStream.connect(inputStream);
ThreadRead threadRead = new ThreadRead(readData,inputStream);
threadRead.start();
Thread.sleep(2000);
ThreadWrite threadWrite = new ThreadWrite(writeData,outputStream);
threadWrite.start();
}catch (IOException e){
e.printStackTrace();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
运行结果
inputStream.connect(outputStream)或者outputStream.connect(inputStream)的作用使两个Stream之间产生通信链接,这样才可以将数据进行输出与写入
同理PipeReader和PipeWriter一模一样
3.join的使用
join的作用是:等待线程销毁,或者说join是使所属的线程对象x正常执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后再继续执行线程z后面的代码
方法join具有使线程排队运行的作用,与synchronized的区别是join在内部使用wait()方法进行等待,而synchronized关键字使用的是对象监视器原理作为同步
线程join和intercept相遇,同样会抛出InterceptedException异常(凡是方法使用时候需要抛出这个异常的 一般都会和intercept冲突,例如sleep),代码如下
ThreadA
public class ThreadA extends Thread {
@Override
public void run() {
for(;;){
//我什么也不做,静静看着你俩打
}
}
}
ThreadB
public class ThreadB extends Thread {
@Override
public void run() {
try{
ThreadA a = new ThreadA();
a.start();
a.join();
System.out.println("B要等A完事儿在打印");
}catch (InterruptedException e){
System.out.println("B发现出事儿了");
e.printStackTrace();
}
}
}
ThreadC
public class ThreadC extends ThreadA {
private ThreadB threadB;
public ThreadC(ThreadB threadB) {
super();
this.threadB = threadB;
}
@Override
public void run() {
threadB.interrupt();
}
}
Run类
public class Run {
public static void main(String[] args) {
try{
ThreadB threadB = new ThreadB();
threadB.start();
Thread.sleep(500);
ThreadC threadC = new ThreadC(threadB);
threadC.start();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
此时运行会抛出InterruptedException异常
join(long)的使用
join(long)的效果和sleep(long)一样,区别是join(long)内部是wait(long)方法实现的,所以join(long)方法具有释放锁的特点,而sleep(long)不具备此效果,可以通过查看源码来证实
也因为join(long)会释放锁,所以可能会导致join后面的代码先执行,出现意外
4.ThreadLocal的使用
ThreadLocal为每个线程绑定自己的值,存放每个线程的私有数据,具有隔离性
InheritableThreadLocal具有值继承,值继承再修改特性