JavaSE梳理十四:进程与线程
进程
是程序的一次动态执行过程。它经历了从代码加载、执行到结束的完整过程。这个过程也是进程从产生、发展到消亡的过程。
多线程
是实现并发机制的一种有效手段。多线程是一个线程在执行过程可以产生多个线程,这些线程可以同时存在、同时运行,一个进程可能包含多个同时执行的线程。
线程(Thread):
程序的运行流程,多线程机制指同时运行多个程序块,使程序的执行效率变高。
实现多线程方式:
1.继承Thread类,
2.实现Runnable接口
两者方式的区别:如果一个类继承了Thread类,那么不适合于多个线程共享资源。而实现Runnable接口适合。
多线程中哪个线程获得了CPU资源,哪个线程就运行。
实现Runnable接口的优势?
1,适合多个相同程序代码处理同一资源
2,避免单继承带来的局限性(处理循环时,可以让别的线程先执行)
3,增强代码的健壮性,代码可以被多个线程共享,代码与数据是独立的
为什么启动线程不能使用run方法?
答:线程的运行需要本机操作系统支持,start方法可以运行的原因是:被调用的是start0方法,这个方法表示调用本机操作系统函数。Thread类中的run方法调用的是runnable的run(),这个是需要runnable子类完成,所以想要通过继承Thread实现多线程,必须覆写run()。
如果是继承Thread类,那么一个线程只能调用一次start方法,多次调用会抛出异常“IIlegalThreadStateException”。局限:单继承。
线程状态
创建、就绪、运行、阻塞、死亡(无法继续运行)
注意:主线程有可能比其他线程先执行结束:因为线程的不确定性,所以可能存在主线程最先执行结束,但是此时其他线程不会受到任何影响,并不会随着主线程的结束而结束。
join()
让一个线程强制执行,线程强制执行期间,别的线程无法执行,必须等到此线程执行结束才能继续执行。
线程礼让yield()
将一个线程暂停将资源让给其他线程。
后台线程 setDaemon()
只要有一个前台线程在运行,则整个Java程序都不会消失,如果设置一个后台线程,这样即使Java程序结束,后台线程依然会继续执行。
问:转成后台的死循环如何关掉呢?
线程优先级
所有的线程在运行前都保持就绪状态,谁的优先级高谁就先执行,一共三个高中低,主方法属于中级,注意:并不是谁的优先级越高谁就一定先执行,这取决于CPU的调度。
线程同步
当多个线程竞争同一个资源时,可能会出现多个线程操作同一资源的同步问题。例如:卖票出现负数。
同步:多个线程在同一个时间段内,只能有一个线程进行,其他线程要等待此线程运行完成后才可以继续执行。
解决资源共享的同步操作有:1 同步代码块,2 同步方法。
同步代码块
sychronized (同步对象){同步代码}
一般都是当前对象this设置为同步对象
同步方法
synchronized 方法返回值 方法名称(参数列表){}
死锁
两个线程彼此等待对方执行结束,造成程序停滞,一般出现在程序运行时。
多个线程竞争同一个资源需要同步资源,过多同步可能会死锁。
生产者与消费者
解决问题:生产者刚放进去名称,内容还没放进去,程序就切换到消费者线程,然后消费者线程将新的名称和旧的内容联系起来——加入同步。
解决问题:生产者放进去多次数据,消费者才开始取数据,或者消费者取完一个数据后,生产者还没放进去数据,消费者又重复取出已取过的数据——加入等待与唤醒。生产者生产一个等待消费者取走,消费者取走一个就要等待生产者生产。
生命周期
创建、就绪、运行、阻塞、终止。
suspend、resume、stop容易导致死锁,不建议使用停止线程的运行:
使用标志位:
sleep和wait
区别:sleep属于Thread类,wait属于Object类;sleep不会释放对象锁,wait会;sleep可以出现在任何地方,wait只能出现在同步代码块或同步方法中;sleep使线程进程阻塞状态,wait使线程进入等待状态(挂起),阻塞级别不同。