基本概念
- 程序:指令集合,静态代码,静态对象
- 进程:动态的,资源分配单位。每个进程分配在不同区域
- 线程:细分进程,是程序内部一个执行路径,是调度与执行的单位,每个线程有独立的运行栈与pc,线程切换开销小
- 一个进程中的多个线程共享相同的内存单元/内存地址->他们从同一堆中分配对象,访问相同对象和变量
一个进程分配一个方法区与堆,一个线程分配一个虚拟机栈与一个PC - java.exe程序至少有三个线程,mian()主线程,gc()回收机制,异常处理线程,当然如果发生异常,会影响主线程。
- 并行:多个CPU同时执行多个任务
- 并发:一个CPU片同时执行多个任务:秒杀,多人做一个任务
Thread
mian中调用run就不是多线程了,只能调用Start
一个对象只能调用一次start。
常用方法:setname;getname;currentname;start;run;
yield释放当前cpu执行权
join:线程a调用线程b的join函数,此时线程a进入阻塞状态,直到线程b执行完后,a才结束阻塞
stop强制结束,不推荐
sleep,阻塞状态
isallve()是否存活
调度,抢占式:高优先级占用低优先级
## Runnable接口
Runnable要好于Thread
- 有共享数据可以直接放数据,Thread可能需要static
- 多继承情况下
联系 - 都需要重写run,都要让线程执行
线程生命周期
线程安全
加入sleep是让错误更加明显,,而非出现错误
错误出现原因:
当一个线程尚未完成所有操作时,其他线程参与进来,也操作了数据
解决方法:
- 同步代码块
synchronized(同步监视器:锁){
//同步需要被同步的
//锁,任何对象
也可以用this,但是得保证同一个
在Thread中慎用this。可以用当前类
给每个对象的锁要唯一
只新建了一个窗口对象,所以object只需要一个
多个对象那就是object类
}
- 同步方法
在继承的方式中,如果new了多个对象,那么只能设置为静态的
同步方法中: - 非静态的同步方法,同步监视器是:this
- 静态同步方法是静态本身
弊端:操作同步代码块只能有一个 线程参与,其他线程需要等待,相当于单线程,效率低
懒汉式线程安全
两种方式,效率低
这种效率高,在有资源时进入,没有资源就不用进入同步块了
死锁
加了个sleep就会出现死锁
lock锁
三步如上
两种相同:都是解决安全问题
相同
- synchronized自动释放
- lock手动启动,结束方式
优先级:lock->同步代码块->同步方法
实现线程交替进行
线程1进入执行,然后wait挂起
线程二进入先执行notify方法,然后线程二wait挂起同时唤醒线程一,但是同时线程二持有锁,所以线程一不能进入。然后wati释放锁
这些方法只能用在同步代码块或者同步方法中,且必须是同步监视器,否则会报IllegalMonitorstarteException异常
这三个方法都定义在Object类中
Sleep与wait的异同:
相同点;一旦执行,使得当前得线程进入阻塞状态
不同点:
- 两个方法声明位置不同,Thread类声明sleep(),object()类声明wait()
- 要求不同,sleep可以在任何地方使用,wait必须在同步代码块和同步方法中
- 如果sleep不会释放锁,wait会释放锁
经典问题,生产者消费者问题
实现Callable接口
- 创建一个Callable类
- 实现call方法
- 创建callable对象
- 将对象放入FutureTask,创建其对象
- FutureTask对象放入Thread,调用start
- get返回得就是call得返回值
其特性:
- Call有返回值
- 可以抛出异常
- 支持泛型
线程池
两个线程并功能不同
连接池属性管理需要用ThreadPoolExector类对象去实现,因为上面那个ExecutorService是接口,没有属性得set方法