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(); } }