停止线程
如果在for循环中interrupted,for循环后续的语句还会执行,线程并非停止,可以抛出异常。
如果在for循环中interrupted,for循环后续的语句还会执行,线程并非停止,可以抛出异常。
在沉睡中停止
如果线程在sleep下停止会怎样?
sleep下停止线程,会清楚停止状态值。
stop暴力停止
stop会抛出ThreadDeath异常;次异常不需要显示的补获。
此方法已被作废;如果使用会导致一些清理工作没能完成,导致数据不一致问题。
使用return停止线程
[图片]
建议使用抛出异常的方式实现线程停止,这样在catch块中可以向上抛
暂停线程
java使用suspend暂停线程,使用resume恢复
suspend与resume的缺陷
- 独占
- 不同步
yield
作用
放弃当前cpu资源,给其他线程。但放弃的时间不确定。
线程的优先级
设置线程优先级有助于“线程规划器”决定下一个执行线程。
使用setPriority
jdk中优先级分为1-10个等级。
优先级的继承特性
如:A线程启动B线程,则B的优先级和A的相同。
优先级具有规则性
- 高优先级的总是大部分先执行。
- 线程谁先执行完和代码调用无关。
优先级具有随机性
- 优先级高的不一定每次都先执行完。
守护线程
- 当进程中不存在非守护线程了,守护线程自动销毁。典型的如垃圾回收线程
- 作用:为其他线程的运行提供便利服务
对象及变量的并发访问
synchronized
方法内的变量是线程安全的
- 方法内部变量时私有的
实例变量是非线程安全的
- 两个线程访问同一个对象的同步方法,一定是线程安全的。
synchronized方法和锁对象
- 访问锁对象的被synchronized修改的的实例方法;是同步的,需要排队访问。
脏读
synchronized锁重入
- 在synchronized的方法或块内部调用synchronized方法或块,jing将可以得到锁。
- 可重入锁:自己可以再次获得自己的内部锁
出现异常,锁自动释放
同步不具有继承性
synchronized同步语句块
synchronized代码块间的同步性
- 当一个线程访问object的一个synchronized(this)同步快时,其他线程对同一个object的其他synchronized(this)同步块的访问是阻塞的,说明,synchronized使用的“对象解释器”只有一个。
任意对象作为对象监视器
- java 支持对“任意对象”作为监视器,任意对象大多数是实例变量及方法参数,使用格式synchronized(非this对象)。
- 多个线程持有同一个对象的“对象监视器”,只能有一个线程可以访问。
- 捕鱼其他锁this争抢this锁,可提高效率。
- 非this监视器必须是同一个对象,如:实例变量。(局部变量不满足)
静态synchronized方法与synchronized(class)代码块。
- 同步静态方法,是对Class对象持有锁。
- 同步class对象和同步静态方法作用一样。
数据类型String的常量池特性
- jvm具有String常量池的缓存功能。
- 不使用String作为锁对象。
同步synchronized方法无限等待与解决
- 使用同步快处理(synchronized(Object))
多线程的死锁
内置类和静态内置类
锁对象的改变
- 持有相同锁对象,线程同步。
- 只要对象不变,对象属性改变,依旧是同步的。
volatile
- 作用:使变量在多个线程间可见。
关键字volatile与死循环
- 从线程公共堆栈中获取变量值,而不是线程的私有栈。
- volatile不支持原子操作。
synchronized与volatile对比
- volatile更加轻量级,性能比synchronized好。
- volatile只能修饰变量,synchronized可以修饰方法,以及代码块。
- 多线程访问volatile不会阻塞。
- volatile保证数据的可见性,不能保证原子性。
- synchronized可以保证可见性和原子性。
- volatile解决的是多线程变量的可见性;synchronized解决的是多线程资源的可见性。
- 线程安全包括:可见性和原子性。
volatile非原子特性
- 使用synchronized进行同步
- 使用AtomicInteger可进行原子操作。
synchronized代码块有volatile同步的功能
- 互斥性和可见性
线程间通信
等待/通知机制(wait/notify)
wait
- wait是object对象的方法
- 在wait之前必须获取对象级别的锁,即只能在同步方法或同步块中调用wait方法
- 调用wait时没有持有适当的锁,则抛出运行时异常illegalMonitorStateException,无需使用try…catch…捕获。
notify
- notify是Object对象的方法。
- 必须获取对象级别的锁,即只能在同步方法或同步块中调用
- 在执行notify后,当前线程不会立即释放该对象的锁,wait的也不会立刻得到该对象锁。
- 执行notify的线程执行完,即退出synchronized代码块,才会释放锁,呈wait的线程才能得到对象锁。
- 第一个获得notify的线程执行完毕,释放对象锁,如果没有发出notify或notifyAll,其他线程也不能获取到对象锁。
- 方法wait被执行后,所被释放;执行完notify后,锁却不被释放;必须执行完notify所在的synchronized代码块才能释放。
- 执行完同步代码块就会释放锁对象。
- 在执行同步代码块的过程中,遇到异常而导致线程终止,会释放锁。
- 在执行同步代码块中执行wait,会释放锁。
notifyAll
- 唤醒所有等待线程
生产者&消费者
==使用notifyAll可以避免程序假死==
通过管道进行线程间通信
pipeStream用于不同线程之间传递数据
join
等待线程对象销毁
- join具有使线程运行的作用,有些类似同步的效果。
- join在内部使用的是wait方法进行等待;synchronized使用“对象监视器”原理做同步。
join与异常
- join与interrupt方法如果彼此相遇,会出现异常。
join(long)与sleep(long)区别
- join释放锁
ThreadLocal
变量共享可以使用public static变量的形式,所有线程都使用同一个public static变量。如果实现每个线程都有自己的共享变量,可以使用ThreadLocal。
ThreadLocal可以比喻全局存放数据的盒子;盒子可以存储每个线程的私有数据。
方法get与null
- ThreadLocal解决的是不同线程之间的隔离性。
InheritableThreadLocal
- 可以在子线程中获取主线程中取值。
- 如果主线程将值改变,则子线程依旧拿到的是旧值。
Lock
ReentrantLock
- lock\unclock
Condition实现等待/通知
- 一个lock可以创建多个Condition对象。
- notify/notifyAll 选择线程是随机的;Condition可以选择性的通知。
- 必须在condition.await()之前调用lock.lock()
- signal/signalAll
公平锁/非公平锁
- 公平锁:按照线程加锁的顺序来分配
- 非公平锁:抢占机制
ReentrantReadWriteLock
- 读锁共享
- 写锁互斥
- 读写互斥
定时器Timer
- 设置计划任务
- 执行任务的类TimerTask
Timer的使用
schedule
- Timer.schedule 启动一个新线程。如果没有设置Timer为守护线程,则则一直运行。
- 执行时间早于当前时间,则任务立刻执行。
- timer中允许多个task。以队列的方式执行,可能和预期的不一致。
TimerTask
- cancel将自身从队列中移除,其他任务不受影响。
- timer的cancel是将队列全部清除。
- Timer类中的cancel类有可能没有抢占到queue的锁,TimerTask类中的任务继续执行。
单例模式与多线程
延迟加载
多线程下,延迟加载时错误的单例模式
解决方法
- synchronized关键字,对getInstance方法加锁。
- 使用DCL双检查锁机制。
使用静态内之类实现单例模式
序列化与反序列化
使用static静态代码块实现单例
- static中的代码在实用类时已经执行。
使用enum枚举类只想单例模式
- 在使用枚举类时,构造方法自动被调用。