- 进程和线程
- 进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。
- 线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。
- 并行和并发
- 并行是在同一时刻同时执行
- 并发是在一个时间段内执行
- 开启线程的方法
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口,有返回值。需要借助FutureTask类,该类实现了Runnable接口
- 中断线程的方法:
- stop(),suspend()方法尽量不要用,stop方法太过激进调用直接终止线程,suspend()方法挂起线程后不释放资源。尽量使用下面的方法
- interrupt()方法,中断线程,并不强行关闭线程。该方法有线程对象决定是否停止。中断标志位置为true
- isInterrupt()方法终止线程,并返回是否已经终止,判断中断标志位置是否为true
- static方法interrupted()中断标志改为false
- 方法会抛出InterruptedException,线程的中断标志位会被复位成false,这时需要在catch里调用interrupt()方法将中断标志设置为true
- 线程的状态
- 新建
- 就绪
- 运行
- 阻塞
- 死亡
- java线程中的方法
- start():将线程由新建状态转入就绪状态
- join():获取执行权,由就绪状态转为运行状态
- yield():运行状态转为就绪状态,当前线程时间片到期,等待下次一次时间片
- run(),stop(),setDeamon()线程运行结束进入死亡状态
- wait():线程由运行状态进入阻塞状态,等待notify()或者notifyAll()唤醒后进入就绪状态
- sleep():线程由运行状态进入阻塞状态,等待sleep时间到或者interrupt()后进入就绪状态
- 线程的优先级
- 1-10,缺省为5,值越高分配的时间片越大
- 不同的操作系统对优先级的作用不同,有的操作系统会忽略优先级,所以线程优先级不可靠
- 守护线程
- 和主线程共死的,主线程退出,守护线程也会退出
- 设置成守护线程setDaemon(true),必须在start方法前使用
- 守护线程中的finally不能保证一定会执行
- 线程间的共享
- Synchronized内置锁都是锁对象
a)对象锁:动态方法上
b)类锁 :每个类的class对象 - volatile关键字,最轻量的同步机制,最适用只有一个线程写,多个线程读的场景,只能确保可见性。像整型数自加等操作不能确保其原子性
- ThreadLocal关键字。每个线程只能使用自己线程的拷贝。尽量存储一个占用内存比较小的数据结构,否则比较耗内存。比如Integer。
- Synchronized内置锁都是锁对象
- 线程间的协作
- wait
- notify和notifyAll
- 等待方的标准范式:
a, 获取对象的锁
b, 判断循环条件是否满足,不满足调用wait方法 - 通知方的标准范式:
a, 获取对象的锁
b, 改变条件
c, 通知所有等待对象的锁 - 尽量使用notifyAll,因为使用notify可能会发生信号丢失,使用notify可能会解锁对象的某一个线程锁,不能解锁对象的其他线程锁,当出现有多个线程对对象使用wait()时,会出现有线程的锁无法解开
- 等待超时模式实现一个连接池
- join()方法
- 可以解决多个线程按顺序执行
- 线程A执行了线程B的join方法,线程A必须等待线程B执行完后才能继续执行
- 调用yield(),sleep(),wait(),notify等方法对锁有何影响
- 调用yield()以后,持有的锁不释放
- 调用sleep()以后,持有的锁不释放
- 调用wait()方法之前必须持有锁,调用方法后,锁会被释放;当wait()方法返回的时候,当前线程重新持有锁
- 调用notify()或notifyAll()方法之前必须持有锁,调用notify()或notifyAll()方法本身不会释放锁。等当前锁模块执行完后才释放锁
网友评论