多线程概念
多线程在实际项目中经常用到,通常用在整个业务中,没有太大的前后关联性,简单的来说就是相互关联性很低,而在多线程中常会面临着数据一致性的问题
三大特性
- 原子性:数据的一致性,保证数据同步
- 可见性:java内存模型,主内存与本地私有内存
- 有序性:线程之间的通信:wait notify join
java内存模型
- 分为主内存与本地私有内存,共享变量存储在主内存中,创建线程时,线程会把主内存中的变量拷贝一份副本到自己的本地私有内存中,操作完变量后,会把私有内存中的变量刷新到主内存中,这时主内存中的变量就更新了。
进程与线程
- 进程: 正在执行的应用程序,是一个独立的单元,也是多线进程的集合。 eg:qq 微信
- 线程:单个进程中独立运行的一个任务。
- 在一个进程中运行多个线程,每个线程相互是独立的,互不影响,同时使用多线程会提高程序的执行效率
- 在多线程中通常使用实现runable接口的方式,这种创建多线程的方式是面向接口开发,比继承Thread方式更通用
- 多线程中主线程与子线程执行没有先后顺序,根据cpu调度决定谁先执行
多线程的生命周期
- 新建
- 就绪
- 运行 —> 阻塞 —> 休眠 调用sleep/wait方法
- 结束
线程的分类
- 守护线程:通常是指守护线程,类似GC线程,也可手动创建守护线程
- 用户线程:通过常规方式创建线程,java虚拟机中所有非守护线程释放后,用户线程就释放了
1. 区别:
- 守护线程与用户线程实现的效果是相同的,唯一的区别是,用户线程结束后,守护线程随之结束,用户线程不会等待
- 守护线程:手动创建时,必须在线程调用start方法之前,调用setDaemon方法,设置当前线程为守护线程,
2. 应用场景:
- 举个栗子:客户端请求后台,后台采用的是多线程方式,客户端1请求后台时,会新创建一个线程为客户端1服务,在来一个客户端2,请求后台时,会新创建一个新的线程为客户端2服务,每一个请求后台服务器都会有一个单独的线程处理,并且线程之前是不会相互影响的。
线程池的四种类型
- 可缓存型: cach,在线程池中添加多个线程时,线程池会复用已经创建好的线程
- 可自定义线程数:fixed,可设置线程池中线程的个数
- 可定时执行线程:schedule,设置几秒后执行线程池中线程
- 单例执行,单线程类型:single,线程池中只能运行一个线程
join的用法
- 如果有2个线程:T1 T2
在T1中使用T2.join(),则T1会阻塞,让出cpu让T2先执行,等T2执行结束后,T1才会执行
synchronized
常用在线程同步问题中
- 举个栗子:商品与消费者,如果消费者采用多线程的方式去消费商品,而商品的数量是有限的,这样会导致商品剩余数量为负数,这种情况肯定是不能出现的,常用的解决方式就是采用线程锁,保证每一个线程在消费商品的时候,其他线程处于等待状态
这样就达到了线程同步
线程同步分为同步代码块与同步方法
1.同步代码块:通常是将代码中某一块内容进行加锁,可使用对象锁或this
2.同步方法:在方法中声明此方法为同步方法,默认使用的是this
ps:如果同时使用同步代码块和同步方法时,同步代码块必须使用this锁,否则会导致线程资源不同步