-
Notifications
You must be signed in to change notification settings - Fork 0
yangyp8110 edited this page Jan 17, 2018
·
1 revision
ReentrantLock(重入锁),在等待锁的过程中可以中断(可以灵活控制锁范围;可以中断)
public class test1Class {
public static class ReenterLock implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
lock.lock();//仅作演示反复进入,不建议在循环内部使用锁
try{
i++;
}finally {
lock.unlock();
}
}
}
}
}
运行结果:
public void test1() throws InterruptedException {
//重入锁(可反复进入)
test1Class.ReenterLock t1 = new test1Class.ReenterLock();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t1);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
/**
* 200000 --- 第一次执行
* 400000 --- 第二次执行(刷新)
* 600000 --- 第三次执行(刷新)
* ……
*/
System.out.println(test1Class.ReenterLock.i);
}
锁申请等待限时 (预防死锁)
public class test2Class {
public static class TimeLock implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
/**
* tryLock 不带参数时:
* 如果锁未被其他线程占用,则申请锁成功,并立即返回true;
* 如果锁被其他线程占用,则当前线程不会进行等待,立即返回false,申请锁失败
* 所以tryLock不带参数并不会产生死锁
*/
if(lock.tryLock(5, TimeUnit.SECONDS)){//请求锁,等待5秒
Thread.sleep(6000);
}else{
System.out.println(Thread.currentThread().getName() +" get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if(lock.isHeldByCurrentThread()){
lock.unlock();
}
}
}
}
}
运行结果:
public void test2() {
/**
* 输出:(t1持有锁6秒,t2请求锁5秒未获取到)
t2 get lock failed
*/
test2Class.TimeLock timeLock = new test2Class.TimeLock();
Thread t1 = new Thread(timeLock, "t1");
Thread t2 = new Thread(timeLock, "t2");
t1.start();
t2.start();
}
模拟死锁
public class test3Class {
public static class IntLock implements Runnable {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
public int lock;
public IntLock(int lock) {
this.lock = lock;
}
@Override
public void run() {
try {
if (lock == 1) {
//持有锁,同时可以响应中断
lock1.lockInterruptibly();
try {
Thread.sleep(300);
} catch (InterruptedException ex) {
}
lock2.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + " : 线程执行完毕 !"+ lock);
} else {
//持有锁,同时可以响应中断
lock2.lockInterruptibly();
try {
Thread.sleep(300);
} catch (InterruptedException ex) {
}
lock1.lockInterruptibly();
System.out.println(Thread.currentThread().getName() + " : 线程执行成功 !" + lock);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
if (lock1.isHeldByCurrentThread()) {
lock1.unlock();
}
if (lock2.isHeldByCurrentThread()) {
lock2.unlock();
}
System.out.println(Thread.currentThread().getName() + " : 线程退出 !");
}
}
}
}
运行结果:
public void test3() throws InterruptedException {
/**
* 模拟死锁(由于t2中断,t1获取lock2锁,继续执行)
* 如果将 t2.interrupt(); 注释,程序陷入死锁,永远不能结束
*
* 输出:
t2 : 线程退出 !
java.lang.InterruptedException
t1 : 线程执行完毕 !1
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
t1 : 线程退出 !
*/
test3Class.IntLock intLock1 = new test3Class.IntLock(1);
test3Class.IntLock intLock2 = new test3Class.IntLock(2);
Thread t1 = new Thread(intLock1, "t1");
Thread t2 = new Thread(intLock2, "t2");
t1.start();
t2.start();
Thread.sleep(2000);
//中断一个线程(如果注释,程序进入死锁,永远不能结束)
t2.interrupt();
}
死锁解决办法:
* 1:锁申请等待限时(test2)
* 2:条件触发(test3)
死锁排查
- a.输入 jps 命令; 可以查看java进程id,查看当前java进程(测试用例SpringBoot启动的是ApplicationMain)
输出进程中找到 226776 ApplicationMain
- b.输入 jstack 226776
C:\Windows\system32>jstack 226776
2017-06-07 23:01:40
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.101-b13 mixed mode):
****省略一部分***
=========================
学家B":
iting to lock monitor 0x000000000bd9ed98 (object 0x00000000db70c140, a
.Object),
ich is held by "哲学家A"
学家A":
iting to lock monitor 0x000000000bd9d798 (object 0x00000000db70c150, a
.Object),
ich is held by "哲学家B"
stack information for the threads listed above:
===============================================
学家B":
at concurrency.demo.projects.model.chapter3.DeadLock.run(DeadLock.
- waiting to lock <0x00000000db70c140> (a java.lang.Object)
- locked <0x00000000db70c150> (a java.lang.Object)
学家A":
at concurrency.demo.projects.model.chapter3.DeadLock.run(DeadLock.
- waiting to lock <0x00000000db70c150> (a java.lang.Object)
- locked <0x00000000db70c140> (a java.lang.Object)
d 1 deadlock.
公平锁 ReentrantLock(true) ; 非公平锁 ReentrantLock() --默认非公平锁
重入锁 Condition(条件)
- Condition与Object.wait()、Object.notify()相似,wait和notify是和synchronized搭配,Condition是与ReentrantLock搭配使用
Semaphore(信号量)
/**
* Created by mr.yang on 2017/6/6.
*
* 以下例子每次执行3个线程(每次允许3个线程访问资源,释放(semaphore.release())掉后可以有线程允许访问)
*/
public class test4Class {
public static class SemapDemo implements Runnable{
final Semaphore semaphore = new Semaphore(3);
@Override
public void run() {
try {
//申请信号量(如果未申请到,则等待)
semaphore.acquire();
Thread.sleep(2000);
System.out.println("id:"+Thread.currentThread().getId()+",name:"+Thread.currentThread().getName()+": done !");
//释放信号量
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
public void test4(){
/**
* 信号量 (Semaphore)
* 对锁的扩展,锁一次只允许一个线程访问一个资源;而信号量可以指定多个线程同时访问一个资源
*
* 以下例子每次执行3个线程(每次允许3个线程访问资源,释放(semaphore.release())掉后可以有线程允许访问)
*/
ExecutorService executor = Executors.newFixedThreadPool(20);
test4Class.SemapDemo demo = new test4Class.SemapDemo();
for (int i = 0; i < 20; i++) {
executor.submit(demo);
}
System.out.println("finished");
}
ReadWriteLock(读写锁)
CountDownLatch(倒计时) countDown.countDown() : 倒计时递减 countDown.await() : 等待倒计时归0 //用于检查步骤都完成了
CyclicBarrier(循环栅栏) 每完成一批计数,计数器会归0,然后执行任务;紧接着进行下一批计数,循环往复
线程池(Executors线程池工厂)
- newFixedThreadPool 创建固定数量的线程池,线程数量始终不变。任务提交到线程池,如有空闲线程,则立即执行;没有空闲线程,会将任务保存在一个任务队列中,等有空闲 线程时,再处理空闲队列中的任务
- newSingleThreadExecutor 返回只有一个线程的线程池。任务提交到线程池,如有空闲线程,则立即执行;没有空闲线程,会将任务保存在一个任务队列中,等有空闲 线程时,再处理空闲队列中的任务
- newCachedThreadPool 返回可以根据实际情况调整线程数量的线程池。线程池的线程数量不确定。任务提交到线程池,如有空闲线程可复用,则优先使用可复用的线程; 没有空闲线程,会创建新的线程处理任务,处理完成后会返回线程池进行复用。
- newSingleThreadScheduledExecutor 返回ScheduledExecutorService对象,线程池大小为1,ScheduledExecutorService接口在ExecutorService接口之上扩展了 在给定时间执行某任务的功能(在某个固定的延时之后执行 或 周期性执行某个任务)
- newScheduledThreadPool 返回ScheduledExecutorService对象,并且可以指定线程池的线程数量
- 定时任务(ScheduledExecutorService不会造成任务堆叠)
schedule : 在给定时间对任务进行一次调度
scheduleAtFixedRate :周期性调度(如果执行任务时间 8s 调度时间 2s 则任务会8s一次频率调用)
scheduledWithFixedDelay :间隔时间调用(在上一次调用结束后,间隔指定时间调用下一次任务)
- 定时任务(ScheduledExecutorService不会造成任务堆叠)
实际上是对ThreadPoolExecutor的封装,ThreadExecutor超负载了的拒绝策略:
Fork/Join框架
- 可以通过ForkJoinPool的submit方法向ForkJoinPool线程池提交一个ForkJoinTask任务
- ForkJoinTask有两个重要的子类:
- RecursiveAction(没有返回值的任务)
- RecursiveTask(有返回值的任务)