您当前的位置: 首页 >  Java

命运之手

暂无认证

  • 2浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【Java】【Thread】Java线程同步API详解

命运之手 发布时间:2019-04-29 14:54:17 ,浏览量:2

?线程状态的定义 新建状态:thread刚被new出来,还没有执行start方法,只是一个尚未开始工作的对象 就绪状态:thread执行了start方法,但是尚未获得CPU资源,这个状态一般只会持续一瞬间 运行状态:thread获得CPU资源,开始执行代码 阻塞状态:thread因为sleep,wait,sychronized,join等方法,暂时挂起,让其它线程先执行 死亡状态:thread的run方法完全执行完毕

我们先弄清楚各种api的作用,然后再来分析每个方法执行时,线程状态是如何切换的

由于Thread很多api要强制进行异常处理,为了更简洁直观地展示核心代码,封装了一个Threads类,把异常处理代码屏蔽了 Threads.post()相当于new Thread().start() Threads.sleep()相当于Thread.sleep() Threads.wait()相当于Thread.wait() Threads.join(t)相当于t.join() Threads.interrupt(t)相当于t.interrupt()

?thread.sleep(long ms) 线程休眠等待一段时间再执行

?synchronized(lock) {…} 同步块,线程锁定lock对象的访问和修改权限,简称线程获得lock对象锁,只有当前线程退出{…}代码块,或者主动让出对象锁时,其它线程才能使用lock对象

?synchronized void function() {…} 同步方法,同一时间只有一个线程可以进入该方法,必须当前线程退出方法后,其它线程才能进入该方法

?lock.wait() 只有在同步块中,才能使用此方法,让出lock的对象锁,进入阻塞状态,直到其它线程调用lock.notify()或lock.notifyAll()来通知自己,才恢复到就绪状态

?代码测试 代码如下,t1调用了wait后,t2没有调用notify,t1会无限等待 在这里插入图片描述

?lock.wait(long timeout) 和wait()功能一致,增加了超时处理,当超出timeout指定的时间时,即使其它线程没有调用lock.notify(),线程也会自动进入就绪状态

?代码测试 代码如下,t1调用了wait后,t2没有调用notify,t1到达超时时间,自动往下执行 在这里插入图片描述

?sleep和wait方法的区别 sleep是线程的方法,wait则是同步对象的方法 sleep只是单纯地让线程休眠等待,和其它线程没有任何交互 wait方法涉及到的是对象锁,本质是线程同步,线程间资源争夺,其它线程调用notify,退出同步块,都会影响到正在wait的线程

?lock.notify() 通知另一个wait状态的线程退出wait状态,具体哪个线程会被通知,是不确定的,由系统调度来决定 线程退出wait状态后,并不是立刻执行代码,仍然要等待对象锁,只有其它线程释放了对象锁,或者退出了同步块,当前线程重新抢到对象锁后,才能继续执行代码 建议尽量把nofify放在sychronized同步块最后一行执行,因此就算提前调用了notify,如果还没有退出同步块,被通知的线程还是无法获得对象锁

?lock.notifyAll() 通知所有执行了lock.wait()的线程退出wait状态,其它特性和notify()方法一致

?代码测试 代码如下,t1调用wait后,t2进入同步块,t2调用wait后,t3进入同步块,t3退出同步块,t1继续执行,因为notify只通知了一个线程,所以t2永远处于wait状态 如果代码里面改成调用lock.notifyAll(),则t1和t2都会执行全部语句 在这里插入图片描述

?thread.yield() 放弃CPU资源,从运行状态转入就绪状态,让其它线程获得CPU的概率高一点 这是一个不太常用的API,告诉系统可以先把手中的CPU资源让给其它线程使用,用于让步CPU资源 它只是一个建议性的API,提高其它线程优先执行的概率,只有微弱的作用,效果并不稳定 这个API只是暂时放弃了手中的CPU资源,从而提高其它线程先执行的概率,但是很快线程就会重新CPU资源,继续执行 这个API和线程同步,线程阻塞毫无关系

?代码测试 代码如下,通过setPriority()给线程设置优先级,t1设置了最高优先级,t2设置了最低优先级,重复运行多次,t1大多是先于t2打印的 注意:线程优先级也是建议性的,即使t1和t2的优先级相差极大,也有可能不按优先级来执行,只是高优先级的线程,先执行的概率会高点 接着,我们在t1的中间调用thread.yield()方法,再观察运行结果,可以看到,t1执行了一半,t2获得了CPU开始执行 注意:setPriority()和yield()都是建议性的方法,会影响线程获得CPU的概率,但并不会产生太明显的效果,比如t1执行了一秒,t2尚未执行,这种情况是很难出现的 我们的代码之所以能看出明显效果,是因为执行语句很少,CPU还没来得及切换线程,代码都已经执行完毕了 在这里插入图片描述 在这里插入图片描述

?注意,thread.sleep()和thread.yield()都是静态方法,是对当前线程进行操作 不管调用t1.sleep()还是t2.sleep(),实际上调用的都是Thread.sleep(),不是在操作t1或t2,而是在操作当前线程

?thread.join() 让另一个线程先执行,执行完毕当前线程再继续执行 在这里插入图片描述

?thread.join(long timeout) 和thread.join()功能一致,增加了超时处理,当其它线程过了timeout时长后,仍未执行完的话,当前线程将继续执行 thread.join(0)相当于thread.join(),一直等待其它线程执行完毕

?thread.interrupt() 中断一个阻塞状态的线程,并抛出一个InterruptedException 这个方法只能打破线程的阻塞状态,并不是让线程停止,如果对于非阻塞状态的调用此方法,没有任何作用

?代码测试 让t2休眠1秒,t1休眠3秒,这样就可以保证在t2在调用interrupt时,t1仍然处于阻塞状态 由于没有处理异常,线程t1直接崩溃 在这里插入图片描述 这次我们给t1的sleep加上异常处理 可以看出,处理完异常后,t1继续执行后面的代码,并没有停止 在这里插入图片描述 这次我们让t1因为对象锁而阻塞,t1先休眠1秒,这样t2就可以先拿到对象锁,t1阻塞,t2去中断t1 我们可以看到,在t2退出同步块之后,t1仍然继续执行,没有发生任何异常 这说明interrupt()方法对同步块造成的阻塞无效 在这里插入图片描述 这次来测试wait状态,让t2休眠1秒,这样t1就可以先拿到对象锁进入同步块,执行阻塞代码,再在t2线程中中断t1 和我们测试sleep时的效果完全一样,t1被中断,产生了InterruptedException异常,由于没有处理异常,t1线程直接崩溃 在这里插入图片描述 通过以上测试我们可以总结出 interrupt()方法可以中断线程的wait和sleep状态,但并不会停止线程,线程是否继续运行,取决于开发者如何对异常进行处理

最后,我们再测试一个特殊案例,如果先中断,再阻塞会怎么样? 这次我们在线程启动后,直接将其中断,我们在线程中先执行100万条打印语句,这样就能保证主线程中的interrupt()比子线程中的sleep()先执行 在这里插入图片描述 可以看到,只要一个线程调用了interrupt()方法,即使当时并非阻塞状态,稍后只要进入了阻塞状态,照样会抛出InterruptedException异常

?volatile变量 保证每个线程中访问到的变量值都是最新的 在Java的内存模型中,为了保证速度,每个CPU都有一个高速缓存,线程使用变量时,首先访问的并不是内存中的值,而是CPU缓存中的值,这样当多个线程使用不同CPU的时候,就有可能会出现变量值不一致的情况(大致知道这样一个原因就行,感兴趣的可以自行学习Java内存模型) volatile关键字能够保证被其修饰的变量,当数值被改变时,可以及时反映到内存和各个CPU缓存中,这样每个线程在获取变量值是,都可以保证变量的值是最新的

使用情景:在只有赋值语句,获值语句的简单情况下,一个volatile关键字就可以保证变量的一致性和线程的同步性 但在更多时候,保证变量的值是最新的,并不代表就不会出现同步问题 在这里插入图片描述 这样的一行语句,实际包含了3个操作,获取sum的值,将获取的sum值加1产生新的值,将新的值赋给sum 在执行第二步的时候,sum的值可能已经被其它线程修改了,但是当前线程使用的还是之前获取的值 所以,volatile仅仅适用于只有赋值取值的极其简单情况,连【sum++】【result = !result】这样的简单语句,volatile都无法保证同步性

?如果想了解更多关于Java线程同步,并发编程的进阶知识,可以去学习下concurrent包下的ThreadLocal,Atomic,Lock,ConcurrentCollections,Condition,Executor等类

关注
打赏
1654938663
查看更多评论
立即登录/注册

微信扫码登录

0.0440s