1.线程
和进程区别:
- 进程:独立地址空间 代码、数据、堆栈 资源分配基本单位
- 线程:共享地址空间 线程ID、指令指针、寄存器集合和堆栈 调度分派基本单位
1.1.使用
- 实现Runable接口,run方法为实际逻辑
- 实现Callable接口,可以有返回值,通过FutureTask进行封装再进入Thread参数
- 继承Thread类
- 不能继承其他类
- 开销过大
1.2.状态
特指Java虚拟机的状态,而不是操作系统中的
- NEW 创建未启动,其他状态start会产生IllegalThreadStateException异常。
- RUNNABLE 正在Java虚拟机中运行
- BLOCKED 请求获取monitor lock从而进入synchronized函数或者代码块,但是后者已经被占用
- WAITING 等待线程显式唤醒,阻塞是被动的,等待是主动的,通过调用Object.wait等方法进入。
- 未设置Timeout参数的wait方法
- 未设置参数的join方法
- LockSupport.part方法
- TIMED_WAITING 等待一段时间后自动唤醒
- Thread.sleep
- 设置时间参数的join方法
- 设置时间参数的wait方法
- LockSupport.parkNanos方法
- LockSupport.parkUntil方法
- TERMINATED 死亡,线程自己结束或者异常结束
1.3.常用方法
1.3.1.静态
- interrupted 返回当前线程是否被中断
- sleep 休眠当前线程,单位为毫秒
- yield 作为给线程调度器建议,告诉可以切换给其他线程执行了
- currentThread 当前正在执行的线程
1.3.2.实例
- setDaemon 设置后台服务线程,负责给其他非守护线程提供服务,所有非守护进程结束时守护线程消亡,如垃圾收集线程。守护线程在程序结束时中断不应该产生不良后果,如数据库录入等不能设置为守护线程。
- getName
- getId
- interrupt()
- isAlive
- getPriority 获取优先级
1.4.线程中断相关内容
- InterruptedException 调用线程的interrupt来中断线程,如果线程阻塞,就会抛出该异常提前结束线程,无法阻断IO阻塞和synchronized阻塞。
- interrupted 读取interrupt方法设置的中断标记,如果没有sleep的无限循环无法用interrupt方法抛出异常使其终止。
- isInterrupted 判断是否发生了中断。
- Executor中断操作,shutdown方法等待全部方法执行完毕。shutdownNow,相当于调用每个进程的interrupt方法再关闭。
- Executor的submit方法会返回Future对象,可以调用cancel方法停止他。
1.5.线程协作/通信
按次序完成某个任务,如下的命令都是在多个线程的情况下调用才有意义。
-
join B线程中调用A线程的join,需要等待A线程结束之后再继续B的语句,B会放到阻塞队列。
-
Object的方法
- wait 使线程挂起,等待其他线程用notify由JVM指定和notifyAll将其唤醒,后者让其竞争锁
- 只能在同步方法或者同步控制块中使用
- 使用wait挂起期间,线程会释放锁,如果没有释放,那么其他对象就没法进入对象同步方法或者同步控制块
- wait是Object的方法,会释放锁,sleep是Thread的方法,不会释放锁
- 每个锁对象有两个队列,就绪队列存放将要竞争锁的线程,阻塞队列存储了阻塞的线程
-
Condition的方法
- 使用Lock.newCondition来获得一个Condition对象
- await使线程等待
- singal或者singalAll唤醒等待线程,比wait更加灵活
-
BlockingQueue 使用阻塞队列进行通信
-
sleep和wait的区别
wait | sleep | |
---|---|---|
同步 | 只能在同步上下文中使用 | 任何地方都可以调用 |
作用对象 | 定义在Object中,作用于对象 | 定义在Thread中,作用于当前线程 |
释放锁资源 | 是 | 否 |
唤醒条件 | 其他线程使用notify或者notifyAll | 超时或者调用interrupt方法 |
方法属性 | 实例方法 | 静态方法 |
1.6.线程安全
多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为。
1.6.1.不可变
- final 关键字修饰的基本数据类型
- String
- 枚举类型
- Number 部分子类,如 Long 和 Double 等数值包装类型,BigInteger 和 BigDecimal 等大数据类型。但同为 Number 的原子类 AtomicInteger 和 AtomicLong 则是可变的。
对于集合类型,可以使用 Collections.unmodifiableXXX() 方法来获取一个不可变的集合。其对原始集合进行拷贝,需要对其修改的方法都会抛出异常。
1.6.2.互斥同步
synchronized
- synchronized
- 用在代码块时作用于同一个对象,两个对象上的同步代码块不会进行同步。由monitorenter和monitorexit指令实现,每个对象都是一个监视器锁monitor,被占用就会处于锁定状态。
- 用在方法时也是作用于同一个对象。通过ACC_SYNCHRONIZED标示符号