一、线程之间的通信
定义:
多个线程并发执行时,默认情况下是随机切换线程的
如果我们希望它们有规律的执行,就可以使用通信
线程之间也不是随机干预线程也是随机的
常用方法
wait()让当前线程处于等待状态,并释放锁
notify()唤醒某个等待中的线程
notifyAll()唤醒所有等待中的线程
注意事项
线程间的所有通信行为都必须在同步代码块中执行
这些行为都是锁调用的
当一个线程陷入等待, 线程会释放掉锁, 并且无法动弹, 即使被唤醒了, 也仅仅表示有了获取锁的机会, 只有当真正获取到锁的时候才能继续运行
wait方法还有重载的方法,可以传入毫秒值,表示多少毫秒之后当前线程自动唤醒
一个锁只能唤醒被自己锁定的线程
无法在当前同步代码块内操作别的锁
ThreadLocal
ThreadLocalsshi线程的本地变量,是一个存储变量的容器,存入到这个容器中的变量可以在线程的任意位置取出
ThreadLocal.中的变量是使用线程分离的,别的线程无法使用,保证了线程的安全性
互斥锁
定义
使用ReentrantLock类代替synchronized关键字, 提供了锁定和解锁的方法
提供了更多的操作所得方法
常用方法
lock() 锁定当前线程
unlock() 解锁
newCondition() 获取可以操作线程等待和唤醒的Condition对象
await() 让当前线程陷入等待
signal() 唤醒某个被锁定的线程
线程的七种状态
初始状态:线程创建完成
就绪状态:线程可以被执行
运行状态:线程正在运行中
阻塞状态:线程被休眠
等待队列:线程陷入无限的等待
锁池状态:线程被唤醒,但是没有获取到锁
死亡状态:线程执行完毕,被关闭
注意事项
大部分书籍里都讲线程的状态分为5类, 既初始, 就绪, 运行, 阻塞, 死亡
但我们更愿意将阻塞状态细分出来, 因为 阻塞, 等待队列, 锁池, 完全是不同的性质
线程组
java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,java允许程序直接对线程进行控制
提供了一些整体的方法,比如设置线程中的权限,销毁所有的线程等等。
线程池
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用
在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
Runtime类
定义
这是一个单例类, 可以运行系统命令
public static void main(String[] args) throws IOException {
Runtime runtime = Runtime.getRuntime();
runtime.exec("shutdown -s -t 300");//300秒后关机
runtime.exec("shutdown -a"); //取消关机
}
Timer类
定义
定时器, 可以在指定时间执行任务, 可以重复执行
其实就是在指定时间去调用某个方法
任务类必须继承TimerTask类,并且重写run()方法
常用方法
schedule(TimerTask task,Date time ) 安排在执行时间执行任务
schedule(TimerTask task,Date time , long period) 安排在指定时间开始执行任务, 并按固定时间长度重复执行
schedule(TimerTask task, long delay) 从当前时间延迟一段时间执行任务
schedule(TimeTask task,long delay,long period) 从当前时间延迟一段时间执行任务,并按固定时间长度重复执行