公平锁非公平锁
区别:是否可以插队(默认都是非公平锁)
设置公平锁:new ReentrantLock(ture)
可重入锁(递归锁)
可以理解为:拿到外面的锁就会获得里面的锁
//Synchronized
public class Demo1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sms();
},"A").start();
new Thread(() -> {
phone.sms();
},"B").start();
}
}
class Phone {
public synchronized void sms() {
System.out.println(Thread.currentThread().getName()+"sms");
call();
}
public synchronized void call() {
System.out.println(Thread.currentThread().getName()+"call");
}
}
//lock
public class Demo2 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(() -> {
phone.sms();
},"A").start();
new Thread(() -> {
phone.sms();
},"B").start();
}
}
class Phone2 {
Lock lock = new ReentrantLock();
public void sms() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"sms");
call();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void call() {
try {
System.out.println(Thread.currentThread().getName()+"call");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
自旋锁(spinlock)
写一个自旋锁
//自旋锁
public class SpinlockDemo {
AtomicReference<Thread> atomicReference = new AtomicReference<>();
//加锁
public void myLock() {
Thread thread =Thread.currentThread();
System.out.println(thread.getName()+"===> mylock");
while (!atomicReference.compareAndSet(null, thread)) {
System.out.println(thread.getName());
}
}
//解锁
public void myUnLock() {
Thread thread =Thread.currentThread();
System.out.println(thread.getName()+"===> myunlock");
atomicReference.compareAndSet(thread, null);
}
}
测试
public static void main(String[] args) throws InterruptedException {
SpinlockDemo lock = new SpinlockDemo();
new Thread(() -> {
lock.myLock();
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.myUnLock();
}
},"T1").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
lock.myLock();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.myUnLock();
}
},"T2").start();
}
乐观锁
自我理解:为了提高并发效率,获得更高的吞吐量,默认不会出现冲突,在读取时做个标记,更改时根据标记判断数据是否更改,更改则回滚,未更改在更改。(不会一直占用直到提交时才去锁定)
乐观并发控制的事务包括以下阶段:
- 读取:事务将数据读入缓存,这时系统会给事务分派一个时间戳。
- 校验:事务执行完毕后,进行提交。这时同步校验所有事务,如果事务所读取的数据在读取之后又被其他事务修改,则产生冲突,事务被中断回滚。
- 写入:通过校验阶段后,将更新的数据写入数据库。
悲观锁
悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作。
共享锁
共享锁指的就是对于多个不同的事务,对同一个资源共享同一个锁。(悲观锁的一种)
排它锁
排它锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。
与共享锁类型,在需要执行的语句后面加上for update就可以了
行锁
行锁,由字面意思理解,就是给某一行加上锁,也就是一条记录加上锁。
表锁
表锁,和行锁相对应,给这个表加上锁。
死锁问题
死锁是什么
两个对象互相争抢对方的锁
如:
public class DeadLockDemo {
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new MyThread(lockA,lockB),"T1").start();
new Thread(new MyThread(lockB,lockA),"T2").start();
}
}
class MyThread implements Runnable{
private String lockA;
private String lockB;
public MyThread(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+"lock:"+lockA+"=>get"+lockB);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+"lock:"+lockB+"=>get"+lockA);
}
}
}
}
解决问题
1、使用jps -l
定位进程号
2、使用jstack 进程号
找到死锁问题