1、线程的基本概念
thread.start()方法和runnable.run()方法的区别是:start是新启动一个线程,而run方法只是一个方法的调用,不会启动新线程。
创建线程两种方法:1 实现runnable接口 2 继承Thread类 优劣:java是单继承多实现,所以实现runnable接口更优。
2、线程状态
线程间的状态转换:
1. 新建(new):新创建了一个线程对象。
2. 可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。
该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
3. 运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
4. 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。
直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。
当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
5. 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
3、控制线程状态之sleep、join、yield、priority
sleep:线程休眠,暂时停止执行毫秒
join:由多线程变为了单线程。相当于方法的调用,子线程start以后调用join,那么主线程会等子线程执行完以后再执行。(合并某个线程)
yield:让出cpu,自己暂停,给其他线程执行的机会。
priority:优先级,线程调度器按照线程的优先级决定调度哪个线程执行,优先级范围1-10,默认是5
4、线程终止
方法一:interrupt
方法二:stop
方法三:while()设置布尔变量操控循环操作
第三种最好,第二种最次。方法一和方法二的区别:interrupt以后会跑异常,然后执行捕获异常的操作,而stop是直接死掉,连异常都没有(泼凉水和直接一刀的区别)【run方法结束,线程就结束】
5、线程同步
使用条件:两个子线程同时操作一个变量,所以线程改变量加锁,读不加锁(效率降低)。
synchronized关键字:当执行这段代码的时候锁定方法所在当前对象,当另外一个线程也要访问这段加锁代码的时候得等锁打开。也就是执行完成。保证同一个时间段里面只能有一个线程访问加锁的这段方法。但并不保证其他未加锁方法的执行与否。
public synchronized void test() {
// synchronized (this) {
num++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-----" + num);
// }
}
两种同步方法等价,都表示执行这段方法的时候锁定this对象,如果其他方法也加了synchronized,不能执行,得等这段方法执行完毕,释放对象锁,才能执行别的加锁方法。
注意:当一个线程访问对象加锁的那个方法的时候,另外一个线程完全可以访问对象未加锁的方法。
6、死锁
两个run方法里面各有两把锁(外部锁和內部锁),注意锁要声明为静态的,其中第一个方法的外部锁是第二个方法的内部锁lock1,第二个方法的外部锁是第一个方法的内部锁lock2,方法一要执行完需要lock2,方法二要执行完需要lock1。
解决方法:1 尽量只锁定一个对象 2 锁的力度加大,需要锁定一间屋子,把整个宫殿都锁上,效率低安全
7 wait、notify
wait:当前对象上的线程停止住,前提是synchronized锁住才能wait,未锁不能wait
notify:叫醒wait在当前对象上的其他的线程,
notifyAll:叫醒所有线程
wait和sleep区别
1)不同对象的方法,wait是object的方法,sleep是线程的方法。
2)执行wait会释放对象锁,sleep不会释放锁,睡着了也抱着锁。
3)wait不确定睡眠的时间,sleep确定阻塞的时间。
生产者消费者