06.16 2018-java必备的面试-volatile/synchronized/wait()/sleep(

1、在Java中 wait()和sleep()方法的不同?

最大的不同是在等待时wait()会释放锁,而sleep()会一直持有锁。wait()通常被用于线程间的交互,sleep()通常被用于暂停执行。

2、synchronized和volatile关键字的作用

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1. 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这个新值对其他线程来说是立即可见的。
  2. 禁止进行指令重排序。volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法和类级别;
  • volatile仅能实现变量的修改可见性,并不能保证原子性;synchronized则可以保证变量修改的可见性和原子性;
  • volatile不会造成线程阻塞;synchronized可能会造成线程阻塞;
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

3、分析如下代码执行完之后输出的结果确定为1000吗?原因是什么?(由于是分析代码,所以不给注释)

2018-java必备的面试-volatile/synchronized/wait()/sleep()

分析代码

答案是不一定,或者不等于1000。原因:在java的内存模型中每一个线程运行时都有一个线程,线程栈保存了线程运行时变量的信息。当线程访问某一个对象值的时候,首先通过对象的引用找到对应在 堆内存的变量的值,然后把堆内存变量的具体load到线程本地内存中,建立一个副本,之后线程就不再和对象在堆内存变量值有任何联系,而是直接修改副本变量的值,在修改完之后的某一时刻(线程退出之前),自动把线程副本的值写到对象在堆中的变量。这样在堆中对象的值就产生变化了。也就是说上面主函数中开启1000个子线程,每个线程都会有一个变量副本,每个线程修改变量都只是临时修改了自己的副本,当线程结束时再将修改的值写入主内存中,这样就出现了线程安全问题。因此结果就不可能等于1000,一般都会小于1000。上面的解释用如下图表示:

2018-java必备的面试-volatile/synchronized/wait()/sleep()

2018-java必备的面试-volatile/synchronized/wait()/sleep()


分享到:


相關文章: