JAVA多线程系列--关键字(volatile,synchronized)

来源:互联网 发布:sql拒绝访问 编辑:程序博客网 时间:2024/05/29 18:38

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不保证原子性





原创粉丝点击