并发与并行:
并发:指两个或多个事件在同一时间段内发生
并行:指两个或多个事件在同一时刻发生(同时发生)
线程与进程
进程:一个内存中运行的应用程序,一个程序运行后至少拥有一个进程。
**线程:**进程中的一个执行单元,负责当将进程中程序的执行,一个进程中至少有一个线程,一个进程可以拥有多个线程,这个应用程序也称之为多线程程序。
总结:一个程序运行至少拥有一个进程,一个进程至少拥有一个线程。
进程概念图:
线程概念图:
线程的调度
分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间
抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),JAVA使用的为抢占式调度。
主线程
定义:执行主方法(main)的线程
单线程程序:java程序中只有一个线程,执行从main方法开始,从上到下依次执行。
代码演示:
原理图:
**单线程的缺点:**当main中前面的方法有错误时,后面的方法就不会被执行。
多线程程序:
创建多线程程序的方式:
第一种:创建Thread类的子类
Thread:
实现步骤:
代码演示:
第二种:声明实现Runnable接口类的实现。然后该类实现run()方法
实现步骤:
代码演示:
Runnable与Thread的区别
在线程使用过程中,我们肯定会用到Runnable与Thread,前者的实现方式是实现其接口即可,后者的实现方式是继承其类。两者实现方式带来最明显的区别就是,1、由于Java不允许多继承,因此实现了Runnable接口可以再继承其他类,但是Thread明显不可以。
2、Runnable可以实现多个相同的程序代码的线程去共享同一个资源(两个线程去执行一个run)如图(图片来源于网络)
3、Runnable的解耦性更好(Runnable的run() 与线程的启动式分开操作的,new不同的Runnable接口实现对象,执行的方法就不同)
多线程执行原理:
单线程与多线程原理对比图解:
Thread类中一些常用的方法
1.start():启动新线程(即调用start方法的线程),并调用当前线程的run方法
2.run():通常需要进行重写,将创建的线程需要执行的操作写在run方法中
3.currentThread():是静态方法,这么用:Thread.currentThread()用来返回执行这一行代码的线程,返回类型为Thread
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字,记得要在start方法之前进行。
6.还可以利用构造器给线程起名字
7.yield():释放当前CPU的执行权
8.join():在线程a中调用线程b的join方法,使得线程a进入阻塞状态(CPU想让它执行也执行不了)直到线程b完全执行完,线程a才结束阻塞状态
9.stop():强制线程生命期结束(不是阻塞),不推荐使用,API中已被废弃
10.sleep(long millitime):是静态方法,让当前的线程阻塞指定的毫秒数。传入的参数是毫秒(1秒=1000毫秒),比如想让线程休息(阻塞)1秒,就写1000。经常在显示倒计时的程序中使用
代码演示:(单线程)
11.isAlive():判断当前线程是否还存活(执行完run方法之后线程就死亡了)
线程安全(lock与synchronized)
图像概述:
解决上述线程安全问题:
下述这样没有问题
如果说给线程加上睡眠就会出现安全问题:
分析线程安全问题
问题总结:就是睡眠导致一个线程还没有执行完就失去了cpu执行权,然后导致一些变量改变但是并没有执行完成,导致结果出错。
现在开始解决线程安全问题(线程同步)
同步代码快:只让一个线程在同步代码块中执行
synchroized(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
解决:
同步代码块的原理:
第二种解决方法(同步方法):
代码:
注意:
第三总静态同步方法:(了解)
注意:
第四种解决方案使用 lock锁
使用步骤:(图片中的代码演示)
・
lock与synchronized的区别
・
・
1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定。
但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中;
2. synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;
而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
3. Lock可以让等待锁的线程响应中断,线程可以中断去干别的事务,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断
4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
5. Lock可以提高多个线程进行读操作的效率。
因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。
・
・
Java sleep和wait的区别
・
线程的状态
线程的六种状态:
线程状态图:
1、TimedWaiting(记时等待状态)
TimeWaiting(记时等待)的两种方式
唤醒的方法:
2、Blocked(锁阻塞状态):没有锁对象
3、Waiting(无限等待状态)
案例说明:
等待唤醒案例:(买卖包子)
需求分析:
代码实现:
顾客模拟的实现:
等待与唤醒机制
线程间的通信:(多个线程之间可以进行合作)
概念图解:
意义:
等待与唤醒机制:
案例分析:
包子类:
包子铺类:
用WHILE(TRUE)包裹同步代码块让它一致处于生成或者不生产包子之间
消费者类:
测试类:
线程池
代码实现:
步骤:
Runnable设置线程任务