赞
踩
哪个关键字可以对对象加互斥锁?(A)
A synchronized
B volatile
C serialize
D static
public synchronized void synMethod(){
//方法体
}
public int synMethod(int a){
synchronized(a){
//一次只有一个线程进入
}
}
public class Ticket { private int num = 100; //卖票过程 public void saleTicket(){ synchronized (this) { if (num > 0) { //模拟出票 try { Thread.sleep((int) (Math.random() * 100)); } catch (InterruptedException e) { e.printStackTrace(); } //卖票 System.out.println(Thread.currentThread().getName() + "售出" + num-- + "号票"); //System.out.println(Thread.currentThread().getName() + "出票完成"); } /*else { System.out.println("售完"); }*/ } } public int getNum() { return num; } } public class TicketTread implements Runnable{ private Ticket ticket; //构造方法使得三个线程运行同一个Ticket对象 public TicketTread(Ticket ticket) { this.ticket = ticket; } @Override public void run() { while (ticket.getNum() > 0){ ticket.saleTicket(); } } }
对于方法3,如果线程进入,则得到当前对象锁,那么别的线程在该类所有对象上的任何操作都不能进行,在对象级使用锁通常是一种比较粗糙的方法。
如果一个对象拥有多个资源,就不需要只为了让一个线程使用其中一部分资源,就将所有线程都锁在外面。由于每个对象都有锁,可以如下所示使用虚拟对象来上锁
class FineGrainLock { MyMemberClass x, y; Object xlock = new Object(), ylock = new Object(); public void foo() { synchronized(xlock) { //xlock对象使用的资源的代码块 } //可以在此进行一部分操作,但不要使用共享资源 synchronized(ylock) { //ylock对象使用的资源代码块 } } public void bar() { synchronized(this) { //xlock和ylock共享资源使用时,写到这部分 } //可以在此进行一部分操作,但不要使用共享资源 } }
在进行多线程编程时能够保证程序执行的正确性,JVM内存模型为我们提供了1.原仔细、2.可见性、3.有序性。
Java内存模型具备一些先天的"有序性",即不需要通过任何手段就能够得到保证的有序性,这个通常也称为happens-before原则。如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。
happens-before原则(先行发生原则):
用来确保将变量的更新操作通知到其他线程, 当把变量声明为volatile类型后, 编译器与运行时都会注意到这个变量是共享的, 因此不会将该变量上的操作与其他内存操作一起重排序. 然而, 在访问volatile变量时, 不会执行加锁操作, 因此也就不会使执行线程阻塞, 因此, volatile变量是一种比synchronized关键字更轻量级的同步机制。
volatile修饰之后变得不一样了:
volatile不能保证原子性,能保证可见性,在一定程度上保证有序性,原因:volatile关键字禁止指令重排序。
volatile关键字禁止指令重排序有两层意思:
volatile的原理和实现机制
前面讲述了源于volatile关键字的一些使用,下面我们来探讨一下volatile到底如何保证可见性和禁止指令重排序的。
下面这段话摘自《深入理解Java虚拟机》:
“观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:
1)对变量的写操作不依赖于当前值
2)该变量没有包含在具有其他变量的不变式中
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
本文转载参考文章:java面试题6 牛客:哪个关键字可以对对象加互斥锁?
原文链接:https://blog.csdn.net/weixin_43392489/article/details/102677511
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。