参考:> https://github.com/chengbingh...java
3.1.1 synchronized 扩展功能:重入锁
jdk1.5以前重入锁ReentrantLook性能好于synchronized, 但jdk1.6 开始优化ReentrantLook, 如今两者的性能相差不大。git
/** * @author ChengBing Han * @date 21:50 2018/6/23 * @description */ public class ReentrantLockTest { static ReentrantLock reentrantLock = new ReentrantLock(); static final Object obj = new Object(); public static void main(String[] args) throws InterruptedException { final Thread t1 = new Thread(new Runnable() { public void run() { System.out.println("T1 lock1"); reentrantLock.lock(); System.out.println("T1 lock2"); reentrantLock.lock(); System.out.println("T1 unlock1"); reentrantLock.unlock(); System.out.println("T1 unlock2"); reentrantLock.unlock(); } }); final Thread t2 = new Thread(new Runnable() { public void run() { synchronized (obj){ System.out.println("t2 lock1"); synchronized (obj){ System.out.println("t2 lock2 "); } } System.out.println("t2 end"); } }); System.out.println("lock============"); t1.start(); Thread.sleep(1000); System.out.println("syschronized=================="); t2.start(); } } 输出: lock============ T1 lock1 T1 lock2 T1 unlock1 T1 unlock2 syschronized================== t2 lock1 t2 lock2 t2 end
中断响应github
public class Interrupted implements Runnable { private Integer state = 0; public Interrupted() { } public Interrupted(Integer state) { this.state = state; } static ReentrantLock reentrantLock1 = new ReentrantLock(); static ReentrantLock reentrantLock2 = new ReentrantLock(); public void run() { try { if(state == 1) { reentrantLock1.lockInterruptibly(); System.out.println("state1===lock1"); Thread.sleep(1000); reentrantLock2.lockInterruptibly(); System.out.println("state1===lock2"); }else if(state == 2){ reentrantLock2.lockInterruptibly(); System.out.println("state2===lock2"); Thread.sleep(1000); reentrantLock1.lockInterruptibly(); System.out.println("state2===lock1"); } } catch (InterruptedException e) { e.printStackTrace(); }finally { if(reentrantLock1.isHeldByCurrentThread()){ reentrantLock1.unlock(); } if(reentrantLock2.isHeldByCurrentThread()){ reentrantLock2.unlock(); } } } public static void main(String[] args) throws InterruptedException { final Interrupted r1 = new Interrupted(1); final Interrupted r2 = new Interrupted(2); final Thread t1 = new Thread(r1); final Thread t2 = new Thread(r2); t1.start(); Thread.sleep(100); t2.start(); Thread.sleep(5000); t2.interrupt(); } } 输出 state1===lock1 state2===lock2 java.lang.InterruptedException at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898) at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222) at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335) at com.hcb.thread.c3_1_retrantlookinterrupted.Interrupted.run(Interrupted.java:39) at java.lang.Thread.run(Thread.java:748) state1===lock2
锁申请等待限时
一个锁只能锁住某个时间段数据库
public class TimeLock implements Runnable{ static ReentrantLock reentrantLock = new ReentrantLock(); public void run() { try { if(reentrantLock.tryLock(3, TimeUnit.SECONDS)){ System.out.println(Thread.currentThread().getName() + " run"); Thread.sleep(6000); }else { System.out.println(Thread.currentThread().getName() + "getLock failed"); } } catch (InterruptedException e) { e.printStackTrace(); }finally { //注意finally 这里释放锁的方式 if(reentrantLock.isHeldByCurrentThread()){ reentrantLock.unlock(); } } } public static void main(String[] args) throws InterruptedException { final TimeLock r1 = new TimeLock(); final Thread thread1 = new Thread(r1); thread1.setName("t1"); thread1.start(); Thread.sleep(100); final TimeLock r2 = new TimeLock(); final Thread thread2 = new Thread(r2); thread2.setName("t2"); thread2.start(); } }
公平锁多线程
public class FairLock { //构造函数为true,表示公平 static ReentrantLock reentrantLock = new ReentrantLock(true); public static class ThreadFair implements Runnable { public void run() { while (true) { try { reentrantLock.lockInterruptibly(); System.out.println(Thread.currentThread().getName() + " run "); } catch (InterruptedException e) { e.printStackTrace(); } finally { if (reentrantLock.isHeldByCurrentThread()) { reentrantLock.unlock(); } } } } } public static void main(String[] args) { final ThreadFair threadFair = new ThreadFair(); final Thread fairThread1 = new Thread(threadFair, "fairThread1"); final ThreadFair threadFair2 = new ThreadFair(); final Thread fairThread2 = new Thread(threadFair2, "fairThread2"); fairThread1.start(); fairThread2.start(); } } output: fairThread1 run fairThread2 run fairThread1 run fairThread2 run fairThread1 run fairThread2 run fairThread1 run fairThread2 run fairThread1 run fairThread2 run fairThread1 run fairThread2 run fairThread1 run fairThread2 run
重入锁的condition条件并发
Condition条件相似与wait,notify方法
备注:Condition的使用注意
一、必须在lock.lock()
和lock.singXX中使用 await/singXXapp
二、方法名是await 不是wait,wait 是object的方法函数
public class ConditionLock { static ReentrantLock reentrantLock = new ReentrantLock(); static Condition condition = reentrantLock.newCondition(); static class ConditionLockThread implements Runnable { public void run() { reentrantLock.lock(); try { System.out.println(Thread.currentThread().getName() + " wait..."); //方法是await不是object的wait condition.await(); System.out.println(Thread.currentThread().getName() + " end wait..."); } catch (InterruptedException e) { e.printStackTrace(); }finally { if(reentrantLock.isHeldByCurrentThread()){ reentrantLock.unlock(); } } } } public static void main(String[] args) throws InterruptedException { final ConditionLockThread conditionLockThread1 = new ConditionLockThread(); final Thread thread1 = new Thread(conditionLockThread1, "ConditionLockThread1"); final ConditionLockThread conditionLockThread2 = new ConditionLockThread(); final Thread thread2 = new Thread(conditionLockThread2, "ConditionLockThread2"); thread1.start(); thread2.start(); Thread.sleep(1000); //必须在 lock.lock/unlock 中间使用 reentrantLock.lock(); condition.signalAll(); reentrantLock.unlock(); } }
容许多个线程同时访问 信号量Semaphore
能够容许n个线程同时访问,结合公平锁。工具
3.1.4 读写锁
ReadWriteLock JDK性能
/** * @author ChengBing Han * @date 14:44 2018/7/7 * @description */ public class ReadWriteLockDemo { public static ReentrantLock lock = new ReentrantLock(); private static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); public static Lock readLock = reentrantReadWriteLock.readLock(); public static Lock writeLock = reentrantReadWriteLock.writeLock(); public static int value; private static int index = 0; public static Object handleRead(Lock lock) { lock.lock(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } System.out.println("read value is " + value); return value; } public static void handleWrite(Lock lock, int newValue) { lock.lock(); try { Thread.sleep(1000); value = newValue; System.out.println("write value is " + value); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public static void main(String[] args) { final long startTime = System.currentTimeMillis(); final Runnable readRunnable = new Runnable() { public void run() { handleRead(readLock); } }; final Runnable writeRunnable = new Runnable() { public void run() { handleWrite(writeLock, ++index); } }; for (int i = 0; i < 10; i++) { final Thread thread = new Thread(readRunnable); thread.start(); } for (int i = 0; i < 10; i++) { final Thread thread = new Thread(writeRunnable); thread.start(); } //为何要在while中输出一些东西呢 //若是仍是一个空的While循环,while 会被优化在-Server模式下 while (value != 10){ System.out.print(""); } final long end = System.currentTimeMillis(); System.out.println("app use :" + (end - startTime)/1000); } }
倒计时(线程个数)器: CountDownLatch
可让n线程都完成任务了,在继续执行某个主线程。例如,火箭发射前有10个检查任务,这时建立10个线程分别处理十个任务,再建立一个发射火箭的线程,每次完成一个检查任务,CountDownLatch 记录一个,这样,能够等10个都完成了,发射火箭的线程再执行。
倒计时器的扩展:循栅栏。
扩展了CountDownLatch,将军让10个士兵为1组, 这样一组的完成相似于CountDownLatch, 若是与多组就用循环栅栏。 能够循环多组。
线程阻塞工具类:LockSupport
提供一些阻塞的功能
3.2.1什么是线程池
同数据库链接池
3.3.2不要重复造轮子:jdk对线程池的支持
Executors 是什么?
一言蔽之:工厂
Executors的介绍: /** * Factory and utility methods for {@link Executor}, {@link * ExecutorService}, {@link ScheduledExecutorService}, {@link * ThreadFactory}, and {@link Callable} classes defined in this * package. This class supports the following kinds of methods: * * <ul> * <li> Methods that create and return an {@link ExecutorService} * set up with commonly useful configuration settings. * <li> Methods that create and return a {@link ScheduledExecutorService} * set up with commonly useful configuration settings. * <li> Methods that create and return a "wrapped" ExecutorService, that * disables reconfiguration by making implementation-specific methods * inaccessible. * <li> Methods that create and return a {@link ThreadFactory} * that sets newly created threads to a known state. * <li> Methods that create and return a {@link Callable} * out of other closure-like forms, so they can be used * in execution methods requiring {@code Callable}. * </ul> * * @since 1.5 * @author Doug Lea */
线程池说明
固定数量的线程池
弊端:若是线程池中有5个任务,第一个任务
/** * @author ChengBing Han * @date 12:19 2018/7/14 * @description */ public class FixThreadPoolTest { public static class MyTask implements Runnable{ public void run() { final long id = Thread.currentThread().getId(); System.out.println("当前线程的id是: " + id); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { newFixedThreadPool.submit(new MyTask()); } } } 经过输出能够看到,10个任务,用池子中的了5个线程 **output:** 当前线程的id是: 13 当前线程的id是: 15 当前线程的id是: 16 当前线程的id是: 13 当前线程的id是: 14 当前线程的id是: 17 当前线程的id是: 15 当前线程的id是: 16 当前线程的id是: 13 当前线程的id是: 14
异常处理
/** * @author ChengBing Han * @date 12:19 2018/7/14 * @description */ public class FixThreadPoolTest { static boolean flag = true; public static class MyTask implements Runnable{ public void run() { if(flag){ flag=false; System.out.println("出现异常"); System.out.println(1/0); System.out.println("异常结束"); } final long id = Thread.currentThread().getId(); System.out.println("当前线程的id是: " + id); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { newFixedThreadPool.submit(new MyTask()); } newFixedThreadPool.shutdown(); } } output: 出现异常 当前线程的id是: 11 当前线程的id是: 14 当前线程的id是: 15 当前线程的id是: 13 当前线程的id是: 12 当前线程的id是: 14 当前线程的id是: 15 当前线程的id是: 11 当前线程的id是: 13 **结论:根据上述输出,能够发现,线程次中有10次调用,某次发生异常,不会影响其它的9次**
定时线程:
/** * @author ChengBing Han * @date 12:24 2018/7/14 * @description */ public class SheduleThreadPoolTest { public static class MyTask implements Runnable{ public void run() { System.out.println("Thread is run which id is : " + Thread.currentThread().getId()); } } public static void main(String[] args) { final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5); scheduledExecutorService.scheduleAtFixedRate(new MyTask(),10,1,TimeUnit.SECONDS); } }
*注意定时的这个线程池和上述的newFixedThreadPool不一样,一旦某个任务出现调度异常,那么后面的任务都不会再执行。==》作好异常处理工做。
*定时任务的两个方法不一样之处在于
scheduleAtFixedRate: 每隔2秒调度一个任务,可是一个任务的时间是8秒(大于2秒)那么实际是8秒调度一个任务。
scheduleWithFixedDelay: 隔2秒调度一个任务,可是一个任务的时间是8秒(大于2秒)那么实际是8+2秒调度一个任务。
3.2.3 线程池的内部实现:该部分待看书