21、锁
21.1 公平锁,非公平锁 默认非公平锁
21.2 可重入锁(递归锁)
Synchronized
public class ReentrantLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{phone.sent();}).start();
new Thread(()->{phone.sent();}).start();
}
}
class Phone {
public synchronized void sent() {
System.out.println(Thread.currentThread().getName()+" sent meaasge");
call();
}
public synchronized void call() {
System.out.println(Thread.currentThread().getName()+" phone to");
}
}
Lock
public class ReentrantLockDemo {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{phone.sent();}).start();
new Thread(()->{phone.sent();}).start();
}
}
class Phone {
Lock lock = new ReentrantLock();
public void sent() {
lock.lock();// lock.unlock,lock.lock必须成对出现
try {
System.out.println(Thread.currentThread().getName()+" sent meaasge");
call();
} finally {
lock.unlock();
}
}
public void call() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+" phone to");
} finally {
lock.unlock();
}
}
}
21.3 自旋锁(CAS)
while循环比较直到条件成立
public class MySpinLock {
public static void main(String[] args) {
MySpinLock lock = new MySpinLock();
new Thread(()->{
lock.myLock();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.myUnlock();
}
}).start();
new Thread(()->{}).start();
new Thread(()->{
lock.myLock();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.myUnlock();
}
}).start();
new Thread(()->{}).start();
}
AtomicReference<Thread> reference = new AtomicReference<Thread>();
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+" myLock");
while (!reference.compareAndSet(null, thread)) {
}
}
private void myUnlock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+" myUnlock");
reference.compareAndSet(thread, null);
}
}
21.4 死锁
产生条件:
- 互斥
- 请求与保持
- 不剥夺
- 循环等待
public class MyDeadlockDemo implements Runnable{
public static void main(String[] args) {
User lockA = new User();
User lockB = new User();
new Thread(new MyDeadlockDemo(lockA, lockB)).start();
new Thread(new MyDeadlockDemo(lockB, lockA)).start();
}
private User lockA;
private User lockB;
public MyDeadlockDemo(User lockA, User lockB) {
super();
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA) {
System.out.println(Thread.currentThread().getName()+" have " + lockA + " get "+ lockB);
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (lockB) {
System.out.println(Thread.currentThread().getName()+" have " + lockB + " get "+ lockA);
}
}
}
}
class User {
}
死锁排查
1、使用jps -l 定位进程号
2、使用jstack 进程号 定位死锁问题
Synchronized锁的优化
JDK6后不断优化,Synchronized提供了三种锁的实现,偏向锁,轻量级锁,重量级锁,还提供自动的升级和降级机制;
偏向锁是为了在没有多线程竞争的情况下尽量减少锁带来的性能开销,在锁对象的对象头上有一个ThreadId字段,当一个线程访问锁时,如果该锁没有被其他线程访问过,即ThreadId为空,那么JVM让其持有偏向锁,并将ThreadId的值设置为当前线程的ID,可重入锁,当该线程下一次访问时,比较ThreadId和线程ID是否一致,如果一致,该线程不会重复获取锁,从而提高程序的运行效率。
如果出现锁的竞争情况,偏向锁被撤销升级为轻量级锁,如果资源竞争非常激烈,会升级为重量级锁。
无线程竞争时偏向锁 , 有程竞争时轻量级锁(自旋锁),
线程竞争激烈时 重量级锁:等待对列 --》需要操作系统调度 重量级锁
当线程数数较少时,自旋锁效率高,线程数多时重量级锁效率高(自旋锁会占用大量CPU资源)