Java语言内置了多线程支持,同时提供了很好用的线程同步机制。
每个Java对象都有一个锁(jdk文档中称为object monitor),这个锁在很多地方都有使用。
1. synchonized方法和synchonized块
线程X中调用a对象的synchonized方法func(),自动等待并获取要获取a对象的锁,方法退出(正常退出或抛出异常退出)时自动释放a对象的锁。这里有个很好的特性,获取和释放锁都是自动进行的,不会出现忘记释放锁的情况。
synchonized块是synchonized方法的扩展,它获取的是synchonized块所指定的对象的锁,synchonized方法相当于synchonized(this)。synchonized块的好处是可以将一个对象作为锁在多个地方使用。
2. Object类的wait() notify() notifyAll()
如果说synchonized是用来做线程同步的,那么Object类的wait() notify() notifyAll()就是用来做线程间通信的。
需要特别注意的是,调用这3个方法之前都要在对应对象的synchonized方法或synchonized块中进行,否则会出现异常。
调用对象m的wait()会使当前线程Y等待,4中情况可能使等待退出:a.wait超时 b.m的notify被调用 c.m的notifyAll被调用 d.线程Y的interrupt被调用。处理第一种都会有InterruptedException异常抛出,因此wait调用需要catch InterruptedException.
常见用法:生产者消费者队列,消费者发现队列q为空时调用q.wait(),生产者向队列加入一个元素后调用q.notifyAll(),此时消费者可以被唤醒
3. Thread类的sleep() interrupt() isInterrupt() interrupted()
可以调用它Thread.sleep()使当前线程睡眠一段时间。
线程Z在睡眠、等待事件、等待IO时,外部可能需要提前唤醒线程Z,这种情况下调用Z的interrupt()即可将它从等待中唤醒,Z线程会收到InterruptedException.
值得一提的是,如果线程在正常工作(非上述的等待状态,如在一个循环中做加法),interrupt()是不能打断它的工作的。如果线程需要知道外界是否调用interrupt(),可以通过isInterrupt()检查。而interrupted()是检查当前线程的isInterrupt()状态并清除状态。
4. volatile变量
volatile变量解决的是这样一个问题:Java中多个线程共享的一个变量,某个线程更新该变量后,其他线程不能保证立即读到最想新的值。
将某个变量声明为volatile,可以保证某个线程对它的修改,后续其他线程读到的都是最新值。
5. atomic变量
atomic变量解决的是另一个问题:Java不保证多线程同时写共享的long, double是原子的,可能出现奇异的值。另外,++或――这种其实是两步的操作就更不能保证原子了。
volatile同时有atomic变量的第一个特性,写原子的。