1.Synchronized
使用范围:1.对于普通同步方法,锁水当前实例对象
2.对于静态同步方法,锁是当前类的class对象
3.对于同步方法快,锁是synchonized内配置的对象
实现原理:JVM要保证每个monitorenter必须有对应的monitorexit与之配对。
任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态;直到monitor被释放。
例子:
/** * Synchronized 举例 * @author niyuelin * */ public class SynchronizedExample { public Integer inc = 0; /** * 方法锁 */ public synchronized void increase1() { inc++; } /** * 代码块锁 */ public void increase2() { synchronized(this){ inc++; } } /** * 对象锁 */ public void increase3() { synchronized(inc.getClass()){ inc++; } } public static void main(String[] args) { final SynchronizedExample test = new SynchronizedExample(); System.out.println("========================111"); for (int i = 0; i < 10; i++) { new Thread() { public void run() { for (int j = 0; j < 1000; j++) test.increase3(); }; }.start(); } while (Thread.activeCount() > 2){ // 保证前面的线程都执行完 Thread.yield(); // System.out.println(Thread.activeCount()); } System.out.println(test.inc); } }
1.volatile
内存语义:1.保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2.禁止进行指令重排序。
实现原理: 1.lock前缀指令会引起处理器缓存回写到内存
2.一个处理器的缓存回写到内存会导致其他处理器的缓存无效
通俗的讲:Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。 但是Volatile不保证原子性
例子1:
public class TestWithVolatile { private static volatile boolean bChanged; public static void main(String[] args) throws InterruptedException { new Thread() { @Override public void run() { for (; ; ) { if (bChanged == !bChanged) { System.out.println("!="); System.exit(0); } } } }.start(); Thread.sleep(10); new Thread() { @Override public void run() { for (; ; ) { bChanged = !bChanged; } } }.start(); } }
输出:
若变量bChanged,有volatile修饰;则程序将立即结束并退出。
若无volatile修饰;则程序不会立即结束退出。
原因:每次使用它都到主存中进行读取,从而导致volatile修饰的值会不一样。
例子2:
/** * volatile不保证原子性 * @author niyuelin * */ public class VolatileExample2 { public volatile int inc = 0; public void increase() { inc++; } public static void main(String[] args) { final VolatileExample2 test = new VolatileExample2(); for(int i=0;i<10;i++){ new Thread(){ public void run() { for(int j=0;j<1000;j++) test.increase(); }; }.start(); } while(Thread.activeCount()>2) //保证前面的线程都执行完 Thread.yield(); System.out.println(test.inc); } }
输出:
小于1000的值。
原因:volatile不保证原子性