Java本身就是个支持多线程的语言
每个Java程序就是一个进程,进程又分线程
进程之间是完全相互隔离的,但是同一个进程的各线程之间,又存在着空间公用和数据共享
程序计数器私有:保证线程切换后能回到正确的位置继续执行
本地方法栈和虚拟机栈私有:保证线程中的局部变量不被其它线程访问到
堆和方法区为线程共享。堆主要存储程序执行过程中创建的对象;方法区主要存放已被加载的对象、常量、静态变量等
多线程的优点:多线程可以提高系统的执行效率,特别是多OI或者在多核CPU上时,使用多线程能充分发挥CPU的性能,避免CPU过多的空闲
多线程的问题:线程的切换需要CPU资源,整体上增加了CPU开销;多线程可能造成内存泄露、死锁、线程不安全等问题
线程的状态:初始状态、运行状态、阻塞状态、等待状态、超时等待状态、中止状态
初始状态:线程被创建出来,但是还没start();
运行状态:线程调用start()等待运行的状态;
阻塞状态:线程被阻塞,等待锁释放的状态;
等待状态:线程需要等待其它线程做一些动作,如通知、中断等;
超时等待状态:线程可以在一定时间后自行返回,而不是一直傻傻的等待;
中止状态:线程已运行完毕;
初始状态调用start()方法,线程进入运行状态,如果需要获取锁,线程进入阻塞状态,等待获取到锁,则继续运行。需要线程间互相配合时,线程可能回到等待状态,等待其它相关线程执行完毕。也可手动设置线程的等待时间,线程便进入超时等待状态,等待时间已过,便再次进入运训状态。线程执行完毕,即为中止状态。
上下文切换
线程调用了sleep()、swit()等方法
线程的时间片用完
线程调用了IO操作,线程被阻塞
此时线程后保留当前线程的上下文,让出CPU,并加载下一个将要执行线程的上下文
死锁:
死锁就是多个线程各自占用了部分系统资源,同时又没有全部拿到自己所需要的全部资源,导致所有线程都在等待对方首先释放资源,互相等待。
死锁形成的条件:1、资源互斥,一个资源同一时间只能由一个线程使用;2、请求与保持条件,线程因请求资源而阻塞时,不释放以获得的资源;3、资源只能由本线程释放,不能被其它线程剥夺;4、各线程间等待形成环状
预防死锁:1、一次请求所有资源,否则就释放所有资源;2、占用资源的线程申请其它资源失败时,释放已有的资源;3、按序申请资源
sleep()和wait()
sleep()仅仅相当于使线程暂停执行,并不释放资源,到时自动唤醒继续执行
wait():线程中止执行,进入等待状态,并释放锁,且线程不会自动唤醒,需要调用同一个对象上的notify()或notifyAll()方法唤醒,使用wait(time)也可以到时自动唤醒
sleep()是Theath类的静态本地方法,wait()是Object类本地方法
wait()是让获得对象锁的线程实现等待,释放当前线程所占用的对象锁,既然要释放对象锁,自然要操作对象
sleep()仅仅是让线程等待,涉及不到对象
new一个Thread,线程进入新建状态,如果执行线程的start()方法,会启动一个线程,并进入就绪状态,当时间片到了之后,就会自动运行run()方法,执行线程。start()会做线程的准备工作,之后执行run()。
但是,如果直接执行run()方法,则仅仅是相当于在main线程中执行了一个普通方法,不是多线程的操作。