乐观锁:
// 保证多个线程使用的是同一个 AtomicInter
private AtomicInteger atomicInteger = new AtomicInteger();
public void m3() {
atomicInteger.incrementAndGet();
}
悲观锁:
public synchronized void m1() {
// 加锁后的业务逻辑
}
// 保证多个线程使用的同一个 lock对象的前提下
ReentrantLock lock = new ReentrantLock();
public void m2() {
lock.lock();
try {
// 操作同步资源
}finally {
lock.unlock();
}
}
import java.util.concurrent.TimeUnit;
class Phone {
public static synchronized void sendEmail() {
try{ TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("----- sendEmail");
}
public synchronized void sendSMS() {
System.out.println("----- sendSMS");
}
public void hello() {
System.out.println("----- hello");
}
}
/**
* 1. 标准访问 两个线程,先打印邮件还是短信
* 2. sendEmail 方法中加入暂停 3 秒钟,先打印邮件还是短信
* 3. 添加一个普通的 hello 方法,先打印邮件还是 hello
* 4. 有两部手机,先打印邮件还是短信
* 5. 有两个静态同步方法,先打印邮件还是短信
* 6. 有两个静态同步方法,有两部手机,先打印邮件还是短信
* 7. 有一个静态同步方法,有一个普通同步方法,先打印邮件还是短信
* 8. 有一个静态同步方法,有一个普通同步方法,两部手机,先打印邮件还是短信
*/
public class Lock8Demo {
public static void main(String[] args) {
Phone phone = new Phone();
Phone phone2 = new Phone();
new Thread(()-> {
phone.sendEmail();
},"t1").start();
try{ TimeUnit.MILLISECONDS.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(()-> {
phone2.sendSMS();
},"t2").start();
}
}
情景一 和 二:
一个对象里面如果有多个 synchronized 方法,某一个时刻内,只要一个线程去调用其中的一个 synchronized 方法了,其他的线程都只能等待,换句话说,某一个时刻,只能有唯一的一个线程去访问这些synchronized 方法,锁的是当前对象 this, 被锁定后,其它的线程都不能进入到当前目前对象的其他的 synchronized 方法
情景三和四:
情景五和六:
情景七和八:
反编译 synchronized 同步代码块:
public class LockSyncDemo {
Object object = new Object();
public void m1() {
synchronized (object) {
System.out.println("----- hello synchronized code block");
}
}
public static void main(String[] args) {
}
}
javap -c .\LockSyncDemo.class:
Compiled from "LockSyncDemo.java"
public class com.bxtech.juc.LockSyncDemo {
java.lang.Object object;
public com.bxtech.juc.LockSyncDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: aload_0
5: new #2 // class java/lang/Object
8: dup
9: invokespecial #1 // Method java/lang/Object."":()V
12: putfield #3 // Field object:Ljava/lang/Object;
15: return
public void m1();
Code:
0: aload_0
1: getfield #3 // Field object:Ljava/lang/Object;
4: dup
5: astore_1
6: monitorenter
21: aload_1
22: monitorexit
23: aload_2
24: athrow
25: return
Exception table:
from to target type
7 17 20 any
20 23 20 any
public static void main(java.lang.String[]);
Code:
0: return
}
反编译 synchronized 普通同步方法:
public class LockSyncDemo {
public synchronized void m2() {
System.out.println("----- hello synchronized code m2");
}
public static void main(String[] args) {
}
}
javap -v .\LockSyncDemo.class :
public synchronized void m2();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String ----- hello synchronized code m2
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 11: 0
line 12: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/bxtech/juc/LockSyncDemo;
反编译 synchronized 静态同步方法:
public class LockSyncDemo {
public static synchronized void m3() {
System.out.println("----- hello synchronized code m3");
}
public static void main(String[] args) {
}
}
javap -v .\LockSyncDemo.class :
public static synchronized void m3();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 19: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 args [Ljava/lang/String;
为什么任何一个对象都可以成为一个锁:
ObjectMonitor() {
_header = NULL;
_count = 0; // 用来记录该线程获得锁的次数
_waiters = 0,
_recursions = 0; // 锁的重入次数
_object = NULL;
_owner = NULL; // 指向持有 ObjectMonitor对象线程
_WaitSet = NULL; // 存放处于 wait 状态的线程队列
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; // 存放处于等待锁 block 状态的线程队列
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
类型 | 说明 |
公平锁 | 是指多个线程按照申请锁的顺序来获取锁,这里类似排队买票,先来的人先买后来的人在队尾排着,这是公平的 Lock lock = new ReentrantLock(true) |
非公平锁 | 是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转或者饥饿状态(某个线程一直得不到锁) Lock lock = new ReentrantLock(false) 或 Lock lock = new ReentrantLock() |
import java.util.concurrent.locks.ReentrantLock;
class Ticket{
private int number = 50;
ReentrantLock lock = new ReentrantLock(true);
public void sale() {
lock.lock();
try {
if(number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出第:\t" + (number--) + "\t 还剩下:" + number );
}
}finally {
lock.unlock();
}
}
}
public class SaleTicketDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(()-> {for(int i = 0; i < 55; i++) ticket.sale(); },"a").start();
new Thread(()-> {for(int i = 0; i < 55; i++) ticket.sale(); },"b").start();
new Thread(()-> {for(int i = 0; i < 55; i++) ticket.sale(); },"c").start();
}
}
为什么有公平锁和非公平锁:
隐式锁(即 synchronized 关键字使用的锁):
public class ReEntryLockDemo {
public synchronized void m2() {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
m3();
System.out.println(Thread.currentThread().getName() + "\t ---- end m1");
}
public synchronized void m3() {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
m4();
}
public synchronized void m4() {
System.out.println(Thread.currentThread().getName() + "\t ---- come in");
}
public static void main(String[] args) {
ReEntryLockDemo reEntryLockDemo = new ReEntryLockDemo();
new Thread(()->{
reEntryLockDemo.m2();
},"t1").start();
}
public static void m1() {
final Object object= new Object();
new Thread(()->{
synchronized (object){
System.out.println(Thread.currentThread().getName() + "\t ---- 外层调用");
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "\t ---- 中层调用");
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "\t ---- 内层调用");
}
}
}
},"t1").start();
}
}
synchronized 重入的实现机理:
显式锁(即 Lock):
static Lock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(()->{
lock.lock();
try{
System.out.println(Thread.currentThread().getName() + "\t ---- 外层调用");
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t ---- 内层调用");
}finally {
lock.unlock();
}
}finally {
lock.unlock();
}
},"t1").start();
}
死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉那他们都将无法推进下去,如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。
产生死锁的主要原因:
死锁代码:
import java.util.concurrent.TimeUnit;
public class DeadLockDemo {
public static void main(String[] args) {
final Object objectA = new Object();
final Object objectB = new Object();
new Thread(()-> {
synchronized (objectA){
System.out.println(Thread.currentThread().getName()+"\t 自己持有A锁,希望获得B锁");
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
synchronized (objectB) {
System.out.println(Thread.currentThread().getName()+"\t 成功获得B锁");
}
}
},"A").start();
new Thread(()-> {
synchronized (objectB){
System.out.println(Thread.currentThread().getName()+"\t 自己持有B锁,希望获得A锁");
try{ TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
synchronized (objectA) {
System.out.println(Thread.currentThread().getName()+"\t 成功获得A锁");
}
}
},"B").start();
}
}
死锁排查: