java线程内通信与跨线程通信

threadLocal, 是线程内通信利器

新建一个threadLocal对象后, 当使用set的时候, 对象会以自身为key, 将set的值存入当前线程对象内的一个map中.

当在线程内想要使用该threadLocal set的值的时候, 直接get就可以拿到, 在jdk 1.5后, 通过threadLocal存放在线程中的 值, 会随着线程的销毁而慢慢被jvm回收掉.

但需要注意的是在springmvc这种框架中, 针对api请求使用了线程池技术, 在单个请求结束后, 线程本身不一定会销毁, 会在新的请求过来的时候重新启用, 针对这种情况, 如果针对每次请求共享数据, 必须在请求结束后remove掉通过 threadlocal set的值

  • demo, 带编写
  • 疑惑, springmvc的请求线程回收时机, 待处理

跨线程通信

在java 单进程中

  • 使用 wait notity notifyAll()

wait 和 notify 必须在 synchronized 代码块中, 且synchronized对象必须为同一个

不建议直接使用wait 和 notify , 建议使用java.util.concurrent包中的并发组件

实例demo, 待优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.luozi.thread;

/**
* Created by luoziyihao on 6/20/17.
*/
public class CrossThreadCommunicationByWaitAndNotify {


public void start() {
Object lock = new Object();
boolean[] locked_1 = {false};

Runnable consumerRunner1 = getRunnable1(lock, locked_1);

final boolean[] locked_2 = new boolean[1];
Runnable consumerRunner2 = getRunnable2(lock, locked_2);

Thread thread1 = new Thread(consumerRunner1);
Thread thread2 = new Thread(consumerRunner2);

thread1.start();
thread2.start();

sleepForStart();

doNotify(lock, locked_1[0] && locked_2[0]);


}

private void doNotify(Object lock, boolean b) {
synchronized (lock) {
while (b) {

System.out.println("i am notify now");
lock.notifyAll();
break;
}
}
}

private void sleepForStart() {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private Runnable getRunnable2(final Object lock, final boolean[] locked_2) {
return new Runnable() {
@Override
public void run() {
System.out.println("i am start for wait 2");
doWait(lock, locked_2);
System.out.println("i am wait ok , 2");

}
};
}

private Runnable getRunnable1(final Object lock, final boolean[] locked_1) {
return new Runnable() {
@Override
public void run() {
System.out.println("i am start for wait 1");
doWait(lock, locked_1);
System.out.println("i am wait ok, 1");


}
};
}

private void doWait(Object lock, boolean[] locked_1) {
synchronized (lock) {
try {
locked_1[0] = true;
lock.wait();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}

public static void main(String[] args) {
new CrossThreadCommunicationByWaitAndNotify().start();
}
}

  • 使用 condition, 类似的wait, notify, notifyall的效果

如果在代码中不使用 synchronized关键字, 而使用 Lock, 一般是 ReenTrantLock来做同步控制, 可以使用 lock.newCondition 来达到类似的wait, notify, notifyall的效果

对应的方法变成了 await(), signal(), signalAll()

  • 使用管道流
    pipedInputStream pipedOutputStream
    po.close(pi)

线程A 通过 输入流输入数据, 线程B 通过输出流读取数据

  • 并发队列
    ConcurrentLinkedQuene 非阻塞
    ArrayBlockingQuene LinkedBlockingQuene 阻塞 set满了 或者 poll空了会阻塞住
    ArrayBlockingQuene LinkedBlockingQuene 的区别 循环顺序表 和双向链表