Day11 多线程的学习,线程一些方法的使用
Day11
多线程的学习
线程休眠sleep的使用
sleep可以模拟网络延迟和倒计时。
模拟网络延迟
在线程中使用Thread.sleep()方法,能够放大问题的发生性,能更好的把握问题所在。
比如以前的例子,多个线程同时执行一个资源,会造成一个线程执行全部的结果导致无法看到本身线程的问题,使用sleep延迟后就能放大资源利用的情况,使问题暴露出来。
模拟倒计时
倒计时模拟也很简单,利用一个while循环和一个变量,在循环里面用Thread.sleep(1000)表示一秒过去,要模拟多少秒的倒计时。变量就设置多少,循环结束--自减即可。
同样Sleep方法也可以控制系统对时间的读取,一秒刷新一次等操作
每个对象都会有一把锁,sleep不会释放锁
线程礼让 yield
概念,线程礼让就是让当前执行的线程停止,不阻塞。
礼让不一定成功,意思是让正在执行的线程停止,回到重新竞争的局面。
测试了一下,有两个线程来跑,发现无论加不加礼让线程的方法,对结果的随机性都没什么影响,感觉用处不是很大
唯一的用处就是让正在执行的线程停止来和其他线程重新竞争CPU。
线程强制执行 join
join是比较强制的,能合并线程,等待该线程执行完后,再执行其他线程,这时其他线程会处于阻塞状态。
是需要有实例的线程的方法,运行后强制执行该线程。
此方法会让其他线程陷入阻塞,强制执行一个线程,如果该线程所花费的时间久,很造成资源堆积,很少用。
观测线程状态
如昨天学的线程的五大状态
新生 new后
就绪 Runnable
运行 running
阻塞 blocked
结束 dead
观测状态的方法 Thread.getState()
使用上述的方法就能观测到线程当前的状态。
如果线程已经启动过一次而且已经处于结束状态了,就不能够再启动该线程并且会报错。
线程的优先级
java有一个线程调度器,线程调度器通过优先级来决定调度哪个线程
线程优先级用数字表示1-10;
常用的方法 getPriority serPriority(int xxx) 来检测和设置线程的优先级。
main的默认优先级是5
先设置优先级再启动线程,优先级大的优先执行。
优先级低只是意味着获得的调度概率低,并不是优先级低的就不执行了,都全看CPU的调度。
守护线程
daemon 守护
线程分为用户线程和守护线程。
虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕。
守护线程的用处 后台记录操作日志,监控垃圾,垃圾回收等待。
setDaemon()方法。默认是false,是用户线程,变为true就为守护线程 正常的线程都是用户线程
线程同步机制
发生在多个线程操纵同一个资源。即并发。
线程同步就是一种等待机制,比如取票问题,一个人正在取票,另一个就不能取票,这样就会保证资源的安全。
需要访问对象的线程进入这个对象的等待池形成队列。
队列和锁
为了保证数据在方法中访问的正确性,加入锁机制synchronized
一个线程获得排他锁,独占资源,其他线程等待,这个锁其实可以设置在数据变动时,比如一个语句执行会是数据改变,就可以加入锁,当一个线程执行这个语句,其他线程就不能执行这个语句,当修改完后,其他线程才能修改。
但是也有问题
- 一个线程持有锁,会导致其他需要此锁的线程挂起
- 在多线程的竞争下,加锁,释放锁会导致比较多的上下文切换和调度延迟,引起性能问题。
- 如果一个优先级高的线程等待优先级低的线程释放锁,会造成优先级倒置,引起性能问题
线程三大不安全的案例
买票案例
上面代码写过,一个资源被多个线程操纵时,可能出现剩一个票的情况,其他线程看到剩一个直接就拿了,相当于剩一个票被多个线程拿了,无中生有,肯定不正确也不安全。
银行取钱
可以在取钱机里也可以在网上取,在同时登陆后,由于还没开始取钱,两端的钱数一致,一端把钱取走后,另一端并不知道,依旧取钱,从而造成了不安全的情况。
list添加
由于多个线程同时在list添加,导致会把部分数据覆盖掉,从而造成的不安全。
思考
通过今天的学习,了解到线程一些方法的使用。都比较好理解,然后开始线程的不安全案例,这个我在刚开始线程的学习就遇到过,多个线程对一个资源进行操纵时,会产生一些不安全的情况,这时应该用同步方法来解决,就是用锁。这个方法能够保证数据的安全性,但是缺点也有就是会影响程序的性能。 锁关键字synchronized加上这个就完成了保护操作。
这里在学习操作系统也有了解到