Java并发编程三 线程间通信
线程间通信:多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。就是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。
1.wait/notify
使用wait/notify方法实现线程间通信(wait/notify为Object方法)
- wait和notify必须配合synchronized关键字使用
- wait释放锁,notify不释放锁
/**
* wait/notify 示例
* Created by lyyz on 18-5-9.
*/
public class SyncTest {
private volatile List<String> list = new ArrayList<String>();
public void add(){
list.add("aaaa");
}
public int getSize(){
return list.size();
}
public static void main(String[] args) {
//lock 锁
//wait/notify 必须和synchronized 配合使用
final Object lock = new Object();
final SyncTest syncTest = new SyncTest();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
try {
for (int i=0;i<10;i++){
syncTest.add();
System.out.println(syncTest.getSize());
Thread.sleep(500);
if (syncTest.getSize()==5){
System.out.println("t1 notify t2");
//notify 唤醒等待池中的线程但不释放锁 ,等待池中的线程进入锁池状态,争夺lock锁
lock.notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
if(syncTest.getSize()!=5){
try {
//wait让当前线程进入等待状态,释放持有锁 程序计数器会记录当前的指令的位置,等其他线程唤醒后 继续从当前指令位置继续执行
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2 run");
}
}
},"t2");
t2.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.start();
}
}
2.ThreadLocal
ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本。通过ThreadLocal可以将对象的可见范围限制在同一个线程内。
ThreadLoal通过查看源码可知,其实就是将每一个线程的变量存储到一个Map里
public void set(T value) {
Thread t = Thread.currentThread();//1.首先获取当前线程对象
ThreadLocalMap map = getMap(t);//2.获取该线程对象的ThreadLocalMap
if (map != null)
map.set(this, value);//如果map不为空,执行set操作,以当前threadLocal对象为key,实际存储对象为value进行set操作
else
createMap(t, value);//如果map为空,则为该线程创建ThreadLocalMap
}