多线程难点

synchronized锁升级的过程

注意上图两条主线:匿名偏向锁启动和没启动两种方式。

对象头信息

无论锁现在是何状态,只要调用wait()方法都会升级为重量级锁。

yield()、wait()、sleep()、join()四个方法的介绍 

sleep():

 

是Thread类的静态方法,当前线程将睡眠n毫秒,线程进入阻塞状态。当睡眠时间到了,会解除阻塞,进入可运行状态,等待cpu的到来。睡眠不释放锁(如果有的话)。

wait():

 

是Object的方法,必须与synchronized关键字一起使用,线程进入阻塞状态,当notify或者notifyall被调用后,会解除阻塞。但是,只有重新占用互斥锁之后才会进入可运行状态。睡眠时,会释放互斥锁。

注意:因为wait()方法使用在synchronized修饰的范围内,所以:无论锁现在是何状态,只要调用wait()方法都会升级为重量级锁。

yield():

 

yield方法可以暂停当前正在执行的线程对象,让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃cpu执行权而不能保证使其它线程一定能占用cpu,执行yield()的线程有可能在进入到就绪状态后马上又被执行。

join():

A线程调用join代表A线程要插在当前线程的前面执行;通过join()方法的源码可知,它的底层还是wait()方法,一般join() 适用于需要控制线程执行顺序的场景中。 

sleep()和wait()方法的异同:

  • sleep 方法没有释放锁,而 wait 方法释放了锁 。
  • sleep 通常被用于暂停执行;Wait 通常被用于线程间交互/通信
  • sleep() 方法执行完成后,线程会自动苏醒。或者可以使用 wait(long timeout)超时后线程会自动苏醒。wait() 方法调用后,线程不会自动苏醒,需要别的线程调用一个对象上的 notify() 或者 notifyAll() 方法
  • sleep 方法和 wait 方法都可以用来放弃 cpu 一定的时间,不同点在于如果线程持有某个对象的监视器,sleep 方法不会放弃这个对象的监视器,wait方法会放弃这个对象的监视器

为什么wait()的时候必须释放锁?

当线程A进入synchronized(obj1)中之后,也就是对obj1上了 锁。此时,调用wait()进入阻塞状态,一直不能退出synchronized代码块;那么,线程B永远无法进入synchronized(obj1)

同步块里,永远没有机会调用notify(),岂不是死锁了!这就涉及一个关键的问题:在wait()的内部,会先释放锁obj1,然后进入阻塞状态,之后,它被另外一个线程用notify()唤醒, 去重新拿锁!其次,wait()调用完成后,执行后面的业务逻辑代码,然后退出synchronized同步块,再次释放锁。

Thread.sleep(0)的作用是什么?

由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取cpu控制权的情况,为了让某些优先级比较低的线程也能获取cpu 控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡cpu控制权的一种操作。

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...