Java分布式应用学习笔记03JVM对多线程的资源同步和交互机制
int i=0;public void add(){this.i ++ ;}?如果在同一个时刻,客户端有多个人同时调用了此代码块的add方法。会出现i的值可能会出现与预期结果不符的现象。咱们将时间放慢,就用显微镜看看JVM是如何处理this.i ++ ;这简简单单的一行代码的。
public void add() {synchronized (this) {this.i++;}}
?这个几乎是家喻户晓了,在该线程的对象上加锁,拿到传国玉玺,挟天子以令诸侯,别的诸侯谁也别想下圣旨,皇帝在我(当前执行线程)手里呢。执行i++后该线程释放对此对象的持有锁,交出玉玺,也该让别人过过类似曹操的隐了吧。这就是所谓的互斥,保证了在同一个时间段,对同步对象进行加锁后,别人就在执行队列中等待着,再来一个君主,看到曹操还没爽够呢,得了,和刘备一起在执行队列中等着吧,等曹操爽够了,皇帝、玉玺没用了,交出锁,释放对象锁。根据队列的先进先出原则,按道理是该刘备抢到玉玺,也过把隐!
还有lock和unlock方法和synchronized功能类似。一般情况下使用的概率较少,因为得成对出现。
private Lock lock = new ReentrantLock();public void add() {lock.lock();this.i++;lock.unlock();}
?volatile修饰变量,虽然减少了线程不安全的概率,但是呢不能从根本上完全解除。
volatile int i = 0;
?因为用volatile修饰的变量,是直接在堆区进行操作,根本就不复制到操作工作栈。节省了每条代码的中间过程。
package thread;/** * * @author liuyan */public class TestNotify {public static void main(String[] args) {TestNotify testNotify = new TestNotify();ThreadB b = testNotify.new ThreadB();System.out.println("b is start");b.start();/*try {Thread.currentThread().sleep(5);} catch (InterruptedException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}*/synchronized (b) {try {System.out.println("Waiting for b to complete");// 暂时放弃对象锁,让主线程暂停,让ThreadB开始执行b.wait(); } catch (InterruptedException e) {e.printStackTrace();}System.out.println("Final Total is:" + b.total);}}class ThreadB extends Thread {int total;public void run() {synchronized (this) {System.out.println("ThreadB is running");for (int i = 0; i < 100; i++) {total += i;}// 执行完毕,唤醒被暂停的线程notify(); }}}}
?在主线程启动新线程b,主线程与新线程同时run,继续往下走。主线程相当于曹操,线程b相当于刘备。主线程使用wait方法交出b对象的持有锁,等待线程b使用完成后释放对象锁,主线程才能继续拥有对象b的对象锁,继续往下走自己的路。
?