1. 多线程基础回顾
1.1 synchronized关键字
为了防止并发编程引发的数据共享问题,最常见引用的锁机制就是利用synchronized关键字
1 | /** |
上述代码中synchronized
关键字锁住的是堆内存中的Object o
对象,而不是引用 o
。
1.2 synchronized关键字对当前类对象加锁
如上小节所示,每次锁对象的时候,都 new 一个要锁的对象,未免太麻烦,不如锁一个现成的对象:this
1 | /** |
上面代码与下面代码等同:
1 | /** |
1.3 synchronized 锁住静态方法的时候
当有static
存在的时候,synchronized
关键字锁住的是静态类的 .class 类对象(java.lang.Class 类)
1 | /** |
1.5 synchronized
关键字解决线程重入问题
下面代码中,如果类 T 的 run() 方法没有 synchronized 锁机制保护方法体里的代码,那么会出现线程重入的问题而导致的数据不一致问题。
1 | public class T implements Runnable { |
输出奇怪的结果:
1 | THREAD0 count = 8 |
从上述示例可知:synchronized 代码块中的数据操作是原子操作,原子操作在多线程操作数据资源中是不可分割的,因为当某个线程得到锁的时候,其他无法获取到这把锁,而需要等待获得锁,获得的前提条件是:已获得锁的线程执行完锁代码块中的资源操作之后释放掉锁。
1 | /** |
执行结果始终是:
1 | THREAD0 count = 9 |
1.6 同步方法和非同步方法可以同时被多线程调用
下面示例中:m1() 方法是同步方法,m2() 方法是非同步方法,
1 | /** |
执行结果:m1 打印的过程之中, m2 也打印了出来,因此可以得出结论,m1() 方法被线程运行的时候,其他的非同步方法可以被其他线程调用运行,也就是 synchronized 方法块在执行的过程中,非 synchronized 方法是可以被执行的。
1 | t1 m1 start... |