Copyright © 2015 Powered by MWeb, Theme used GitHub CSS.
##线程间通信
多线程访问 volatile 修饰的变量都需要从共享内存中获取,而对它的修改必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。
可以修饰方法或者以同步代码块的形式来使用,确保多个线程在同一时间只能有一个线程处于方法或者代码块中,保证了线程对变量访问的可见性和排他性。
同步代码块的底层实现是 monitorenter 和 monitorexit 指令,而同步方法则是一开方法修饰符上的 ACC_SYNCHRONIZED 完成。
生产者、消费者模型
wait()/notify()
wait和notify方法都是锁对象来调用。它们必须在被synchronized修饰的方法内。
wait方法会使在临界区内的线程进入等待状态,同时释放被同步对象的锁。
notify方法会唤醒一个因调用了wait方法而处于阻塞状态的线程,使其进入就绪状态。
被重新唤醒的线程会试图重新获取锁的控制权,并继续执行wait之后的代码。
static class Provider implements Runnable {
@SneakyThrows
@Override
public void run() {
synchronized (lock) {
System.out.println("生产者运行开始,当前时间 = " + System.currentTimeMillis());
lock.wait();
System.out.println("生产者运行结束,当前时间 = " + System.currentTimeMillis());
}
}
}
static class Consumer implements Runnable {
@SneakyThrows
@Override
public void run() {
synchronized (lock) {
System.out.println("消费者运行开始,当前时间 = " + System.currentTimeMillis());
lock.notify();
System.out.println("消费者运行结束,当前时间 = " + System.currentTimeMillis());
}
}
}
其运行结果如下:
生产者运行开始,当前时间 = 1609770771102
消费者运行开始,当前时间 = 1609770771103
消费者运行结束,当前时间 = 1609770771103
生产者运行结束,当前时间 = 1609770771103
wait方法执行后,线程会立即释放锁,而notify方法执行后,线程并不释放锁。
static class Provider implements Runnable {
@SneakyThrows
@Override
public void run() {
synchronized (lock) {
System.out.println("生产者运行开始,当前时间 = " + System.currentTimeMillis());
lock.wait();
TimeUnit.MILLISECONDS.sleep(300);
System.out.println("生产者运行结束,当前时间 = " + System.currentTimeMillis());
}
}
}
static class Consumer implements Runnable {
@SneakyThrows
@Override
public void run() {
synchronized (lock) {
System.out.println("消费者运行开始,当前时间 = " + System.currentTimeMillis());
lock.notify();
TimeUnit.MILLISECONDS.sleep(300);
System.out.println("消费者运行结束,当前时间 = " + System.currentTimeMillis());
}
}
}
其运行结果:
生产者运行开始,当前时间 = 1609771313436
消费者运行开始,当前时间 = 1609771313437
消费者运行结束,当前时间 = 1609771313738
生产者运行结束,当前时间 = 1609771314039
从结果上可以证明上述观点。
生产者wait之后,消费者立即开始执行,然而消费者notify后,还要等待sleep时间过后,生产者才重新拿到锁对象。
场景例子:
生产者生产数字到List中,当List中的元素个数为10的时候,发送通知给到消费者,消费者消费List中的元素,使其个数为0.
public class ProviderConsumer {
static int x = 0;
private static List<Integer> list = new ArrayList<>();
private static Object lock = new Object();
public static void main(String[] args) {
Thread a = new Thread(new Provider());
Thread b = new Thread(new Consumer());
a.start();
b.start();
}
static class Provider implements Runnable {
@SneakyThrows
@Override
public void run() {
synchronized (lock) {
while (true) {
TimeUnit.MILLISECONDS.sleep(100);
list.add(x++);
if (list.size() == 10) {
lock.wait();
}
lock.notify();
}
}
}
}
static class Consumer implements Runnable {
@SneakyThrows
@Override
public void run() {
synchronized (lock) {
while (true) {
if (list.size() == 10) {
System.out.println(list);
list.clear();
lock.notify();
}
lock.wait();
}
}
}
}
}
主线程等待子线程执行完成后在接着执行。
join的作用就是等待子线程对象销毁。
static class MyThread implements Runnable{
@SneakyThrows
@Override
public void run() {
TimeUnit.SECONDS.sleep(3);
System.out.println("子线程运行结束");
}
}
@SneakyThrows
public static void main(String[] args) {
MyThread t = new MyThread();
Thread a = new Thread(t);
a.start();
a.join();
System.out.println("主线程运行结束");
}
join使得当前线程等待子线程执行完成之后继续执行当前线程的代码。
join内部使用了wait,所以join方法会释放锁。
ThreadLocal即线程变量,属于线程私有。多个线程之间是隔离的。
是一个以ThreadLocal对象为key,任意对象为value的键值对存储结构,绑定在Thread上。
Thread 中的变量
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal set 方法
public void set(T value) {
Thread t = Thread.currentThread();
// Map 是与当前线程绑定的
ThreadLocalMap map = getMap(t);
if (map != null)
//
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// ThreadLocal 内部类 ThreadLocalMap
static class ThreadLocalMap {
// ThreadLocalMap 内部类 Entry,用的是 弱引用,GC 的时候就会被回收
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
Entry 是 弱引用,发生 GC 就会被回收。
ThreadLocal 本身并不存储,是当做 key 传给内部的 ThreadLocalMap

Copyright © 2015 Powered by MWeb, Theme used GitHub CSS.