Java原生多线程并发方法归纳:
Object.wait:
该方法只能在持有锁的情况下调用,也就是在同步块中,如下所示,调用该方法后,当前线程会被放入obj对象的waiting 池中(注意,一个对象会有连个池,一个是waiting pool,一个是锁的pool), 同时当前线程会释放持有的obj对象的锁。
synchronized(obj){
…
obj.wait();
…
}
wait方法调用后遇到一下集中情况会返回:
1. 其他线程调用obj的notify()或者notifyAll()方法,此种情况下,当前线程会被放入obj对象的pool中,竞争obj的锁,如果竞争到了obj的锁,线程就进入runnable状态
2. 其他线程调用当前线程的interrupt()方法,当前线程抛出InterruptedException,中断状态被清除,用户捕捉到该异常后,自己加以处理
3. wait如果调用时传了超时的时间,时间到了后返回
4. wait也可能在非以上情况下返回,被称作“spurious wakeup”,这种情况不可预料的,很少发生,但确实存在,所以一般调用wait方法时,都是在一个while循环中,返回后检查一下条件,以决定是继续执行后续代码还是继续wait. 如下所示
while(condition check){
wait();
}
*obj.notify():*
唤醒其他阻塞在obj.wait上的线程, 该方法只唤醒一个被阻塞的线程(如果有多个线程调用了obj.wait), 至于是哪一个线程被唤醒,jvm按照某种规则选取,此处不关注这点。obj.notify()不会释放对象锁,被唤醒的线程被放入obj的锁等待池中,去竞争obj的锁,如果获得 锁,就进入runnable状态。
obj.notifyAll():
唤醒所有阻塞在obj.wait上的线程,被唤醒的所有线程都被放入obj的锁等待池中,去竞争锁,获得锁的进程就进入runnable状态。
Thread.interupt():
中断线程,中断情况如下:
1. 如果线程被阻塞在sleep(), wait(), join()方法中,抛出InterruptedException, 同时中断状态被清除。
2. 线程阻塞在InterruptableChannel的io操作上,channel被关闭,怕熬出ClosedByInterruptException,中断状态被设置。
3. 线程最在java.nio.channels.Selector.select(), 方法直接返回,中断状态被设置
4. 非以上情况,中断状态被设置
5.注意线程阻塞在io上(非InterruptableChannel的io), 中断状态被设置,但不会被中断(此处不会被中断指的是线程任然阻塞在io上)
Thread.sleep():
当前线程进入阻塞状态,但不会释放锁持有的锁。
volatile:
关键字,就是告知任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新会共享内存。(多线程中,虽然变量分配的内存在共享内存中,但是每个执行的线程还是可以拥有一份拷贝,这样做的目的是加速程序的执行,这是现代多核处理器的一个显著特性). 编译器一般会对代码做优化,加上volatile后,就是告诉编译器,对该变量的访问不要做优化,对他的访问都是对内存的访问,不要做对寄存器的访问。
ThredLocal:
使每个线程都可以有自己的变量副本,理解这一点的关键是所有的线程都使用同一个对象作为线程体(也就是所有的线程用同一个Worker的对象).
public class Launcher{
public static void main(String[] args) {
Worker w = new Worker();
Thread t1 = new Thread(w,"WORK1");
Thread t2 = new Thread(w,"WORK2");
Thread t3 = new Thread(w,"WORK3");
Thread t4 = new Thread(w,"WORK4");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class Worker implements Runnable{
private Object var;//此变量会被所有使用该对象做线程体的线程共享
private ThreadLocal<String> local = new ThreadLocal<String>();//使用ThreadLocal可以是每个线程都可以有自己的变量
private ThreadLocal<String> local2 = new ThreadLocal<String>();//可以保存另一个线程局部变量
@Override
public void run() {
System.out.println("[" + Thread.currentThread().getName() + " set value:" + Thread.currentThread().getId() );
local.set("" + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("[" + Thread.currentThread().getName() + " get value:" + local.get() );
}
}