synchronized和volatile的区别

synchronized synchronized可以修饰方法和代码块 多线程在执行synchronized方 […]

synchronized

  • synchronized可以修饰方法和代码块
  • 多线程在执行synchronized方法时线程会阻塞
  • synchronized可以保证线程的原子性

volatile

  • volatile的性能比synchronized要高
  • volatile只能修饰变量
  • 多线程访问volatile时线程不会阻塞
  • volatile不能保证线程的原子性

线程原子性是指不能在被拆分的操作。在说的直白点就是我们知道线程在执行时是需要一个前提条件的那就是需要获取到系统CPU的执行资格,虽然线程获取到了执行资格但CPU也可以随时切换,不管线程是否执行完毕。线程原子性就是说如果线程已经获取到了CPU的执行资格,如果线程在没有执行完时,任何线程是不能够中断的。

下面的事例我们演示一下volatile关键字为什么不支持线程原子性。

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo extends Thread {

    public volatile static int count;

    private static void count() {
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println(String.format("count: %s	thread: %s", count, Thread.currentThread().getName()));
    }

    @Override
    public void run() {
        count();
    }
}
/**
 * 测试类
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:49
 * @since 1.0.0
 */
public class RequestRun {
    public static void main(String[] args) throws InterruptedException {
        Userinfo[] userinfos = new Userinfo[100];
        for (int i = 0; i < 100; i++) {
            userinfos[i] = new Userinfo();
        }
        for (int i = 0; i < 100; i++) {
            userinfos[i].start();
        }
    }
}
count: 9200	thread: Thread-66
count: 9600	thread: Thread-62
count: 9800	thread: Thread-60
count: 9700	thread: Thread-61
count: 9900	thread: Thread-59
count: 10000	thread: Thread-58
count: 9300	thread: Thread-65
count: 9400	thread: Thread-64
count: 10000	thread: Thread-63

我们看结果显示Thread-58和线程Thread-63输出count都是10000。这显然是不正确的。原因就是volatile关键字是不支持原子性也不支持同步性的。如果我们把count()方法添加synchronized关键字,那输出结果就是线程安全的了。

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo extends Thread {

    public volatile static int count;

    private synchronized static void count() {
        for (int i = 0; i < 100; i++) {
            count++;
        }
        System.out.println(String.format("count: %s	thread: %s", count, Thread.currentThread().getName()));
    }

    @Override
    public void run() {
        count();
    }
}
count: 9400	thread: Thread-7
count: 9500	thread: Thread-5
count: 9600	thread: Thread-6
count: 9700	thread: Thread-4
count: 9800	thread: Thread-3
count: 9900	thread: Thread-1
count: 10000	thread: Thread-2

我们看结果是线程安全的了。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧