1、实现多线程的方法是1种还是2种还是4种?
Oracle官方:2种,一种是将类声明为Thread子类,第二种是实现Runnable接口。
- RunnableStyle 用Runnable方式创建线程
- ThreadStyle 用Thread方式创建线程
对比:实现Runnable接口更好,java是单继承,多接口,可以解耦
本质:Runnable最终调用target.run();ThreadStyle方法run()整个都被重写
- BothRunnableThread 同时使用Runnable和Thread两种实现线程的方式
准确的讲,创建线程只有一种方式,那就是构造Thread类,而实现线程的执行单元有两种方式
- ThreadPool 线程池创建线程的方法-本质是new Thread
- DemoTimmerTask 定时器创建线程
- AnonymousInnerClassDemo 匿名内部类实现创建线程
- Lambda lambda表达式创建线程
2、启动线程正确和错误的方式
- StartAndRunMethod 对比start和run两种启动线程的方式
- CantStartTwice 演示不能两次调用start方法,否则会报错
* start源码解析:
* 启动新线程检查线程状态
* 加入线程组
* 调用start0()
* run源码解析:
* if (target != null) {
* target.run();
* }
3、如何正确停止线程?
原理:使用interrupt来通知,而不是强制
线程停止的两种情况:1.所有代码都运行完毕;2.有异常出现,异常未被捕获
- RightWayStopThreadWithoutSleep run方法没有sleep或wait方法时,停止线程
- RightWayStopThreadWithSleep 带有sleep的中断线程的写法
- RightWayStopThreadWithSleepEveryLoop 如果在执行过程中,每次循环都调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
- CantInterrupt 如果while里面放try/catch,会导致中断失效,sleep的线程一旦响应中断,会清除线程的中断标记位
实际开发中两种最佳的中断实践
- RightWayStopThreadWithInProd 最佳实践1:catch住了InterruptedExcetion之后,优先选择:
* 在方法签名中抛出异常
* 那么在run()就会强制try/catch
- RunThrowException run无法抛出checked Exception,只能用try/catch
- RightWayStopThreadWithInProd2 最佳实践2:在catch子句中调用Thread.currentThread().interrupt()
* 来恢复设置中断状态,以便于在后续的执行中,依然能够检查到刚才发生了中断
* 回到刚才RightWayStopThreadWithInProd补上中断,让它跳出
响应中断方法总结
Object.wait()/wait(long)/wait(long,int)
Thread.sleep(long,int)/sleep(long)
Thread.join()/join(long)/join(long,int)
java.util.concurrent.BlockingQueue.take()/put(E)
java.util.concurrent.locks.Lock.lockInterruptibly()
java.util.concurrent.CountDownLatch.await()
java.util.concurrent.CyclicBarrier.await()
java.util.concurrent.Exchanger.exchang(V)
java.nio.channles.InterruptibleChannel相关方法
java.nio.channles.Selector相关方法
停止线程错误的方法
总共两大种错误的停止方法:
(1) 被弃用的stop()/suspend()和resume()
(2) 用volatile设置Boolean标记位
- StopThread 错误的停止方法:stop()停止线程,会导致线程运行一半突然停止,
* 没办法完成一个基本单位的操作,会造成脏数据
* 总结:stop是不安全的,会会释放掉对象中所有的监视器(monitor)
* suspend和resume会带着锁休眠,不释放锁,导致死锁
volatile包
- WrongWayVolatile 演示用volatile的局限:part1,演示看似可行的部分
- WrongWayVolatileCantStop 演示用volatile的局限:part2 陷入阻塞时,volatile是无法停止线程的
- WrongWayVolatileFixed 用中断来修复刚才无尽等待的问题
停止线程相关重要函数
- RightWayInterrupted Thread.interrupted()方法的目标对象是“当前线程”,而不管本方法来自于哪个对象
- NewRunnableTerminated 展示线程New,Runnable,Terminated三种状态。即使是正在运行,也是Runnable状态,而不是Running
- BlockedWaitingTimedWaiting 展示Blocked,Waiting,TimedWaiting
- Wait 展示wait和notify的基本用法 1. 研究代码执行顺序 2. 证明wait释放锁
- WaitNotifyAll 3个线程,线程1和线程2首先被阻塞,线程3唤醒它们。notify, notifyAll。 start先执行不代表线程先启动。
wait,notify,notifyAll性质:使用必先拥有monitor,notify只能唤醒一个,属于Object类,类似功能,Condition
- WaitNotifyReleaseOwnMonitor 证明wait只释放当前那把锁
- ProducerConsumerModel 用wait/notify来实现生产者消费者模式 (最好能默写)
- WaitNotifyPrintOddEvenSyn 两个线程交替打印0~100的奇偶数,用synchronized关键字实现
- WaitNotifyPrintOddEveWait 两个线程交替打印0~100的奇偶数,用wait和notify
- SleepDontReleaseMonitor 展示线程sleep的时候不释放synchronized的monitor,等sleep时间到了以后,正常结束后才释放锁
- SleepDontReleaseLock 演示sleep不释放lock(lock需要手动释放)
- SleepInterrupted 每个1秒钟输出当前时间,被中断,观察。
* 1.抛出InterruptedException
* 2.清除中断状态
- Join 演示join
* 作用:因为新的线程加入,所以要等待他执行完再出发
* 用法:main等待thread1执行完毕,注意谁等谁
- JoinInterrupt 演示join期间被中断的效果
- JoinPrinciple join原理,join的代替写法
- CurrentThread 演示打印main, Thread-0, Thread-1
- ID从1开始,JVM运行起来后,我们自己创建的线程的ID早已不是2.
- CantCatchDirectly 说明线程的异常不能用传统方法捕获
- ExceptionInChildThread 单线程,抛出,处理,有异常堆栈 多线程,子线程发生异常
- MyUncaughtExceptionHandler 自己的MyUncaughtExceptionHanlder
- UseOwnUncaughtExceptionHandler 使用刚才自己写的UncaughtExceptionHandler
- MultiThreadsError 第一种:运行结果出错。 演示计数不准确(减少),找出具体出错的位置。
- MultiThreadError 第二种线程安全问题,演示死锁。
- MultiThreadsError3 发布逸出
- MultiThreadsError4 初始化未完毕,就this赋值
- MultiThreadsError5 观察者模式
- MultiThreadsError6 构造函数中新建线程
- MultiThreadsError7 用工厂模式修复刚才的初始化问题
- OutOfOrderExecution 演示重排序的现象 “直到达到某个条件才停止”,测试小概率事件
- FieldVisibility 演示可见性带来的问题
- FieldVisibilityABCD 演示可见性带来的问题
- UseVolatile1 volatile适用的情况1
- NoVolatile 不适用于volatile的场景
- volatile不适用的情况2 不适用于volatile的场景2
- Singleton1 饿汉式(静态常量)(可用)
- Singleton2 饿汉式(静态代码块)(可用)
- Singleton3 懒汉式(线程不安全)
- Singleton4 懒汉式(线程安全)(不推荐)
- Singleton5 懒汉式(线程不安全)(不推荐)
- Singleton6 双重检查(推荐面试使用)
- Singleton7 静态内部类方式,可用
- Singleton8 枚举单例(推荐使用)
- MustDeadLock 必定发生死锁的情况
- TransferMoney 转账时候遇到死锁
- MultiTransferMoney 多人同时转账
- DiningPhilosophers 演示哲学家就餐问题导致的死锁
- ThreadMXBeanDetection 用ThreadMXBean检测死锁
- TryLockDeadlock 用tryLock来避免死锁
- LiveLock 演示活锁问题
- 消失的请求 DisappearRequest
- 对象锁示例1,代码块形式 SynchronizedObjectCodeBlock
- 对象锁示例2,方法锁形式 SynchronizedObjectMethodBlock
- 类锁的第一种形式,static形式 SynchronizedClassStatic
- 类锁的第二种形式,synchronized(*class)形式 SynchronizedClassClass
- 同时访问同步方法和非同步方法 SynchronizedYesAnNo
- 同时访问一个类的不同的普通同步方法 SynchronizedDifferentMethod
- 同时访问静态的synchronized和非静态synchronized方法 SynchronizedStaticAndNormal
- 方法抛异常后,会释放锁 SynchronizedException
- 可重入粒度测试1:递归调用本方法 SynchronizedRecursion
- 可重入粒度测试2:调用类内部另外的方法 SynchronizedOtherMethod
- 可重入粒子测试,调用父类方法 SynchronizedSuperClass
- Synchronized锁与Lock锁类比 SynchronizedToLock
- 反编译字节码 Decompilation
- Lock示例
- ForLoop 演示不用线程池创建线程
- FixedThreadPoolTest 演示newFixedThreadPool
- FixedThreadPoolOOM 演示newFixedThreadPool出错的情况
- CachedThreadPool 演示newCachedThreadPool
- ScheduledThreadPoolTest 演示newScheduledThreadPool
- SingleThreadExecutor 演示newSingleThreadExecutor
- ShutDown 演示关闭线程池
- PauseableThreadPool 演示每个任务执行前后放钩子函数
- ThreadLocalNormalUsage00 两个线程打印日期
- ThreadLocalNormalUsage01 10个线程打印日期
- ThreadLocalNormalUsage02 1000个打印日期的任务,用线程池来执行
- ThreadLocalNormalUsage03 1000个打印日期的任务,用线程池来执行
- ThreadLocalNormalUsage04 加锁来解决线程安全问题
- ThreadLocalNormalUsage05 利用ThreadLocal,给每个线程分配自己的dateFormat对象,保证了线程安全,高效利用内存
- ThreadLocalNormalUsage06 演示ThreadLocal用法2:避免传递参数的麻烦
- ThreadLocalNormalUsage06 演示ThreadLocal用法2:避免传递参数的麻烦
- MustUnlock Lock不会像synchronized一样,异常的时候自动释放锁,所以最佳实践是,finally中释放锁,以便保证发生异常的时候锁一定被释放(悲观锁)
- TryLockDeadlock 用tryLock来避免死锁
- LockInterruptibly 获取锁时,被中断
- PessimismOptimismLock 演示锁可见性保证(乐观锁)
- CinemaBookSeat 演示多线程预定电影院座位
- LockDemo 演示ReentrantLock的基本用法,演示被打断
- GetHoldCount 演示reentrantlock可重入性
- RecursionDemo 递归演示可重入性锁
- FairLock 演示公平和不公平锁两种情况
- CinemaReadWrite 演示ReentrantReadWriteLock具体用法
- NonfairBargeDemo 演示非公平和公平的ReentrantReadWriteLock的策略
- CinemaReadWriteQueue 演示读写锁公平性质
- Upgrading 演示ReentrantReadWriteLock可以降级,不能升级
- SpinLock 自旋锁
- AtomicIntegerDemo1 演示AtomicInteger的基本用法,对比非原子类的线程安全问题,使用了原子类之后,不需要加锁,也可以保证线程安全。
- AtomicArrayDemo 演示原子数组的使用方法