创建线程的方法
- 继承thread
- 实现Runnable接口
currentThread( )方法:返回代码段正在被哪个线程调用的信息。
isAlive( )方法:判断当前的线程是否处于活跃状态。
sleep( )方法:在指定的毫秒数内让当前“正在执行的线程”休眠,正在执行的线程是this.currentThread( )返回的线程。
getId( )方法:取得线程的唯一标识。
停止线程:
thread.stop() unsafe 已废弃
thread.interrupt()
This.interrupted()测试当前线程是否已经中断
This.isInterrupted()测试线程是否已经中断
suspend()和resume()可以暂停线程还可以恢复
yield方法:放弃当前CPU资源
守护线程
java线程中有两种线程,一种是用户线程一种是守护线程。
当进程中不存在非守护线程时,守护线程自动销毁。比如垃圾回收线程。
对象及变量的并发访问
1、synchronized同步方法
使用synchronized声明的方法一定是排队运行的。只有共享资源的读写访问才需要同步化。
2、脏读
在读取实例变量时,此值已经被其他线程更改过了。
3、synchronized锁重入
当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象锁的。
可重入锁的定义:自己可以再次获取自己的内部锁。
4、当一个线程执行的代码出现异常时,其所持有的锁会自动释放。
5、synchronized同步语句块
synchronized方法是对当前对象进行加锁,而synchronized代码块是对某一个对象进行加锁。
6、多线程死锁
由于不同线程在等待不可释放的锁,从而导致所有任务都无法继续完成。
volatile关键字
volatile:使变量在多个线程间可用。强制从主存中获取变量值,而不是运行内存中。
synchronized和volatile比较:
volatile是线程同步的轻量级实现,volatile性能要比synchronized好。
volatile不会发生阻塞,synchronized会阻塞。
volatile能保证数据可见性,不能保证原子性;而synchronized可以保证原子性,也可以保证可见性。
线程间通信
1、使用wait/notify实现线程间通信
2、生产者/消费者模式的实现
3、方法join的使用
4、threadLocal类的使用
1、等待/通知机制的实现
wait方法是使当前执行代码的线程进行等待,该方法用来将当前线程置入“预执行队列”,并且在wait所在的代码行处停止执行,直到接到通知或被中断为止。在调用wait之前,线程必须获得该对象的对象锁。执行完成后释放锁。
notify方法需要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象锁。调用时未获得锁会抛IllegalMonitorStateException。
notifyAll方法可以使所有正在等待队列中等待同一共享资源的“全部”线程从等待状态退出,进入可运行状态。
线程状态切换
2、生产者/消费者模式实现
3、通过管道进行线程间通信:字节流、字符流
pipeStream可以用于在不同线程间直接传送数据。一个线程发送数据到输出管道,另一个线程从输入管道中读取数据。
4、join:主线程等待子线程执行完成后再结束,使用join等待线程对象销毁。
5、threadLocal使用
threadLocal:每个线程绑定自己的值,可以使用threadLocal来存储每个线程私有数据。
Lock的使用
reentrantLock是1.5之后新增的。可以实现线程间同步互斥,与synchronized效果相同且功能更强大。(嗅探锁定、多路分支通知)
1、使用Condition实现等待/通知
关键字synchronized与wait和notify来实现等待/通知模式,reentrantLock与condition结合更加灵活,一个lock对象可穿件多个condition实例,线程对象可以指定注册在哪个condition上,从而有选择的进行线程通知。
2、公平锁与非公平锁
公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即FIFO。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的。
3、reentrantReadWriteLock
reentrantLock具有完全互斥排他的效果,同一时间只有一个线程在执行lock后的任务,这样可以保证实例变量的线程安全,单效率非常低下。
读写锁有两个锁,一个是读操作相关的锁,也称共享锁;一个是写相关锁,也称为排他锁。
在没有写操作时,多个thread可以同时获得读锁,进行写操作时,只有一个thread可以获得写锁。
Timer的使用
timer主要负责计划任务的功能,在指定的时间开始执行某一个任务。
执行计划任务要放在timerTask的子类中。
单例模式与多线程
1、立即加载:使用类的时候已经将对象创建完毕。
2、延迟加载:在调用get方法时再进行new操作。