如何建立一个购物网站,网站开发考研是什么专业,网页升级中紧急自动转跳中,宜兴网站设计目录 1.普通方法
2.静态方法
3.锁对象
4.锁升级过程
5.可重入的锁
6.不公平锁
非公平锁的 lock 方法#xff1a; 1.普通方法 将synchronized修饰在普通同步方法#xff0c;那么该锁的作用域是在当前实例对象范围内,也就是说对于 SyncDemosdnewSyncDemo();这一个实例对象…
目录 1.普通方法
2.静态方法
3.锁对象
4.锁升级过程
5.可重入的锁
6.不公平锁
非公平锁的 lock 方法 1.普通方法 将synchronized修饰在普通同步方法那么该锁的作用域是在当前实例对象范围内,也就是说对于 SyncDemosdnewSyncDemo();这一个实例对象sd来说多个线程访问access方法会有锁的限制。如果access已经有线程持有了锁那这个线程会独占锁直到锁释放完毕之前其他线程都会被阻塞
public SyncDemo{Object lock new Object();//形式1public synchronized void access(){//}//形式2,作用域等同于形式1public void access1(){synchronized(lock){//}}//形式3作用域等同于前面两种public void access2(){synchronized(this){//}}
} 2.静态方法 修饰静态同步方法或者静态对象、类那么这个锁的作用范围是类级别。举个简单的例子
SyncDemo sdSyncDemo();
SyncDemo sd2new SyncDemo();} 两个不同的实例sd和sd2 如果sd这个实例访问access方法并且成功持有了锁那么sd2这个对象如果同样来访问access方法那么它必须要等待sd这个对象的锁释放以后sd2这个对象的线程才能访问该方法这就是类锁也就是说类锁就相当于全局锁的概念作用范围是类级别。
这里抛一个小问题大家看看能不能回答如果不能也没关系后面会讲解问题是如果sd先访问access获得了锁sd2对象的线程再访问access1方法那么它会被阻塞吗
public SyncDemo{static Object locknew Object();//形式1public synchronized static void access(){//}//形式2等同于形式1public void access1(){synchronized(lock){//}}//形式3等同于前面两种public void access2(){synchronzied(SyncDemo.class){//}}
} 3.锁对象 普通同步方法锁是当前实例对象。比如
public synchronized void doLongTimeTaskC() {} 4.锁升级过程 无锁——》偏向锁——》轻量级锁——》重量级锁——》GC锁
5.可重入的锁 可重入的含义指的是同一个线程获得锁之后再不释放锁的情况下可以直接再次获取到该锁
Slf4j
public class SynReentrantDemo {public static void main(String[] args) {Runnable sellTicket new Runnable() {Overridepublic void run() {synchronized (this) {String name Thread.currentThread().getName();log.info(我是run抢到锁的是{}, name);test01();} //正常来说走出临界区这个括号才会释放锁但是再没走出之前又进入test01//而test01需要和本方法一样的锁//如果不可重入的话就将出现死锁了--即test01方法等着释放锁而run方法又不会释放锁//因此synchronized只有可以在不释放run方法的锁的情况下又再次获得该锁才不会有问题}public void test01() {synchronized (this) {String name Thread.currentThread().getName();log.info(我是test01抢到锁的是{}, name);}}};new Thread(sellTicket).start();new Thread(sellTicket).start();}
} 首先应该知道synchronized锁的并不是同步代码块而是锁对象关联的一个monitor对象在java中每一个对象都会关联一个monitor对象而这个对象里有一个变量叫recursions — 中文是递归的意思我想大概是因为递归的时候发生可重入的几率应该是最大的所以才用这个当变量名的吧其实可以将它简单理解为一个计数器。
以上面的栗子为例
1当线程1抢到run方法的执行权即抢到锁时这个recursions的值就变为了1 2线程1接着运行并进入test01方法后发现还是线程1且还是要this这把锁就将recursions的值再1 3当线程1执行完test01方法时recursions的值又-1 4执行完run方法时recursions的值又-1就变为了0也就是表示线程1已经释放了this锁。 5之后其他线程就可以继续抢this锁了。
6.不公平锁 非公平锁的 lock 方法
static final class NonfairSync extends Sync {final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}// AbstractQueuedSynchronizer.acquire(int arg)public final void acquire(int arg) {if (!tryAcquire(arg) acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}
}final boolean nonfairTryAcquire(int acquires) {final Thread current Thread.currentThread();int c getState();if (c 0) {// 这里没有对阻塞队列进行判断if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current getExclusiveOwnerThread()) {int nextc c acquires;if (nextc 0) // overflowthrow new Error(Maximum lock count exceeded);setState(nextc);return true;}return false;
} 公平锁和非公平锁只有两处不同
非公平锁在调用 lock 后首先就会调用 CAS 进行一次抢锁如果这个时候恰巧锁没有被占用那么直接就获取到锁返回了。 非公平锁在 CAS 失败后和公平锁一样都会进入到 tryAcquire 方法在 tryAcquire 方法中如果发现锁这个时候被释放了state 0非公平锁会直接 CAS 抢锁但是公平锁会判断等待队列是否有线程处于等待状态如果有则不去抢锁乖乖排到后面。 公平锁和非公平锁就这两点区别如果这两次 CAS 都不成功那么后面非公平锁和公平锁是一样的都要进入到阻塞队列等待唤醒。
相对来说非公平锁会有更好的性能因为它的吞吐量比较大。当然非公平锁让获取锁的时间变得更加不确定可能会导致在阻塞队列中的线程长期处于饥饿状态。