1. 多线程锁
1.1 锁的机制
- synchronized锁的是当前的对象(this)
- static synchronized锁的是当前类的对象(Class)
- 对于同步方法块,锁是Synchonized括号里配置的对象
1.2 公平锁和非公平锁
- 非公平锁:会造成线程饿死的情况(一个线程把事干完了,其他线程没事可干),效率高。
- 公平锁:让每个线程都有活干,但是效率相对来说低一些。
private ReentrantLock lock = new ReentrantLock(true);//true表示设置为公平锁,非公平锁可能会导致一个线程把所有活都干了
import java.util.concurrent.locks.ReentrantLock;
public class LockSaleTicket {
public static void main(String[] args) {
LTicket ticket = new LTicket();
new Thread(() -> {
for (int i = 0; i < 30; i++) {
ticket.sale();
}
}, "aa").start();
new Thread(() -> {
for (int i = 0; i < 30; i++) {
ticket.sale();
}
}, "bb").start();
new Thread(() -> {
for (int i = 0; i < 30; i++) {
ticket.sale();
}
}, "cc").start();
}
}
class LTicket {
private int num = 30;//票数
//创建可重入锁
private final ReentrantLock lock = new ReentrantLock(true);//true表示设置为公平锁,非公平锁可能会导致一个线程把所有活都干了
public void sale() {
//上锁
lock.lock();
//判断当前是否还有票卖
try {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ":卖出" + (num--) + "剩下:" + num);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//不管有没有异常,都需要解锁
lock.unlock();
}
}
}
1.3 可重入锁
可重入锁,也叫做递归锁
,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码
,但不受影响。
synchronized(隐式)和Lock(显式)都是可重入锁。
代码演示:
public class 可重入锁 {
public static void main(String[] args) {
//synchronized可重入锁的演示
Object o = new Object();
new Thread(() -> {
synchronized (o) {
System.out.println(Thread.currentThread().getName() + " 外层");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + " 中层");
synchronized (o) {
System.out.println(Thread.currentThread().getName() + " 内层");
}
}
}
}, "t1").start();
// add();//因为用的是可重入锁,可以进行递归调用,所以会出现栈溢出
}
public static void add() {
add();
}
}
/*
t1 外层
t1 中层
t1 内层
*/
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Lock演示可重入锁 {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "外层");
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "中层");
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "内层");
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
} finally {
lock.unlock();
}
}, "t2").start();
}
}
/*
t2外层
t2中层
t2内层
*/
1.4 死锁
1.4.1 什么是死锁?
死锁:两个或者两个以上进程在执行过程中,因为争夺资源而造成一种互相等待的现象,如果没有外力的干涉,他们无法再继续执行下去。
1.4.2 产生死锁的原因
- 系统资源不足造成死锁
- 进程运行推进顺序不合适
- 资源分配不当
1.4.3 死锁演示
public class 死锁 {
static Object a = new Object();
static Object b = new Object();
public static void main(String[] args) {
new Thread(()->{
synchronized (a){
System.out.println(Thread.currentThread().getName()+"持有锁a,试图获取锁b");
//增加时间,以免直接执行完了,B线程还没开始
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (b){
System.out.println(Thread.currentThread().getName()+"获取锁b");
}
}
},"A").start();
new Thread(()->{
synchronized (b){
System.out.println(Thread.currentThread().getName()+"持有锁b,试图获取锁a");
//增加时间,以免直接执行完了,A线程还没开始
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (a){
System.out.println(Thread.currentThread().getName()+"获取锁a");
}
}
},"B").start();
}
}
1.4.4 验证是否是死锁
- jps
- jstack jvm自动对战跟踪工具