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

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





发布了72 篇原创文章 · 获赞 52 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/niyuelin1990/article/details/78482037