一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
1.死锁
例子每个线程两个锁都要用到,但是每个线程分别拿了一个锁,然后获取另外的锁,但是当前锁得不到不释放。最终造成卡死的现象
public class TestThreadDeadlock implements Runnable {
private static String lockA = "lockA";
private static String lockB = "lockB";
private AtomicInteger num = new AtomicInteger(1);
@Override
public void run() {
if (num.get() % 2 == 1) {
synchronized (lockA) {
System.out.println("1获取A锁");
num.set(2);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB) {
System.out.println("1获取B锁");
}
}
} else {
synchronized (lockB) {
System.out.println("2获取B锁");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA) {
System.out.println("2获取A锁");
num.set(1);
}
}
}
}
public static void main(String[] args) throws InterruptedException {
TestThreadDeadlock deadLock=new TestThreadDeadlock();
Thread t1=new Thread(deadLock);
Thread t2=new Thread(deadLock);
t1.start();
Thread.sleep(100);
t2.start();
}
}
效果
2.join方法说明
- join 方法可以让线程的并行变为串行
- join 的作用是放弃当前的程序执行,去执行join的线程直到执行结束
- join(long) 设置时间过后变并行 这里会释放锁的,sleep不释放的
- join 放在start前面无意义
- join 实现原理是wait
3.Semaphore信号量
- 信号量可以控制并发访问的个数 例如生产5个可以并发的消费5个
- 信号量和锁之间的区别是锁只有一个线程拿到锁,信号量可以是一批次的
Semaphore semaphore = new Semaphore(10,true);//可以有多少个请求 公平/非公平
semaphore.acquire(); //获取请求 阻塞的
semaphore.release(); //释放请求
4.wait/notify
5.Lock/Condition
可以声明多次:private static Condition c1 = lock.newCondition();
Condition.await();=Object.wait
Condition.await(long,timeUnit);=Object.wait(long)
Condition.signal();=Object.notify()
Condition.signalAll();=Object.notifyAll()
Codition和lock捆绑,wait/notify和同步块捆绑
6.LockSupport
- LockSupport是一个线程阻塞工具类,所有的方法都是静态方法,
- 和wait和notify的功能类似,wait/notify只能在同步块里面使用,LockSupport可以让线程在任意位置阻塞
// 唤醒下一个线程
LockSupport.unpark(t1);
// 当前线程阻塞
LockSupport.park();
7.新建 T1、T2、T3 三个线程,如何保证它们按顺序执行
大概逻辑就是T1执行、唤醒T2执行、唤醒T3执行
- 根据上面学习用join
T1.start();
T1.join();
T2.start();
T2.join();
T3.start();
T3.join();
- 根据上面学习用信号量
Semaphore semaphore1=new Semaphore(1);
Semaphore semaphore2=new Semaphore(0);
Semaphore semaphore3=new Semaphore(0);
默认线程1可以拿到一个许可
线程1拿到许可执行,设置线程2
线程2拿到许可执行,设置线程3
线程3执行
- 根据上面的LockSupport
//执行
//唤醒t2
LockSupport.unpark(t2);
//当前阻塞
LockSupport.park();
//t2先阻塞
LockSupport.park();
//执行
//唤醒t3
LockSupport.unpark(t3);
//t3先阻塞
LockSupport.park();
//执行
//唤醒t1
LockSupport.unpark(t1);
- 锁加状态
/**
* name 打印输出
* targetNum 目标值的时候才匹配输出
**/
private void printLetter(String name, int targetNum) {
//注意这里的循环是匹配状态后才++的 控制打印的次数
for (int i = 0; i < times; ) {
//获取锁
lock.lock();
//状态控制当为目标状态的时候输出
if (state % 3 == targetNum) {
state++;//另一个线程匹配
i++;//循环打印的次数+1
System.out.print(name);
}
lock.unlock();
}
}