多线程8锁
Java的8锁问题链接
8锁即8个关于锁执行顺序的问题
解决问题前,首先需要明白的是 synchronized 只会锁两样东西,一样是调用的对象,一样是Class
一个对象里面如果有多synchronized方法,某一时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一时刻内,只能唯一一个线程去访问这些synchronized方法。锁的是当前对象this,被锁定后,其它的线程不能进入到当前对象的其它的synchronized方法
synchronized实现同步锁的基础:Java中的每一个对象都可以作为锁。
具体表现为以下3种形式:
对于普通同步方法,锁是当前实例对象
对于静态同步方法,锁是当前类的class 对象。
对于同步方法块,锁是synchronized括号里配置的对象。
问题一: 标准访问,请问先打印邮件还是短信?
class Phone {
public synchronized void sendEmail() throws Exception {
System.out.println("------sendEmail");
}
public synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(1000);
new Thread(()->{
try{
phone.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
判断执行顺序,先判断什么被锁了,这里synchronized锁的是Phone对象new出来的phone,因为先调用了sendEmail()睡1秒后调用的sendSMS(),sendSMS()需要等到sendEmail()释放锁后才会执行
输出结果
------sendEmail
------sendSMS
问题二:邮件暂停4秒钟,请问先打印邮件还是短信?
class Phone {
public synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
该情况其实和问题一 一样,synchronized锁的是Phone对象new出来的phone,当调用sendEmail()时,phone被锁,而程序不受sendEmail()内睡的影响继续执行,在调用sendSMS()的时候因为phone被锁导致等待,当sendEmail()执行完后sendSMS()瞬间执行
输出结果
------sendEmail
------sendSMS
问题三:新增一个普通方法hello(),请问先打印邮件还是hello?
class Phone {
public synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public void hello(){
System.out.println("------hello");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone.hello();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
程序执行在sendEmail()中锁了fun并在方法中睡4秒,外部在睡1秒后调用hello(),因为无锁因此直接执行
输出结果
------hello
------sendEmail
问题四:两部手机,请问先打印邮件还是短信?
class Phone {
public synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
Phone phone1=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone1.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
程序调用sendEmail()时锁住phone,外部睡1秒后调用sendSMS()时锁phon1,互不影响
输出结果
------sendSMS
------sendEmail
问题五:两个静态同步方法,同一部手机,请问先打印邮件还是短信?
class Phone {
public static synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public static synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
这里多了静态static,因此此时锁的东西改变了,sendEmail()和sendSMS()都是锁的Phone这个class,程序在执行sendEmail()时锁住Phone class,睡1秒后调用sendSMS(),sendSMS()等待sendEmail()内睡完释放锁后再执行
输出结果
------sendEmail
------sendSMS
问题六:两个静态同步方法,两部手机,请问先打印邮件还是短信?
class Phone {
public static synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public static synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
Phone phone1=new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone1.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
要注意的是,不管现在new结果对象,调用方法后锁的都是Phone class,sendSMS()会被sendEmail()阻塞
输出结果
------sendEmail
------sendSMS
问题七:一个静态的同步方法,一个普通同步方法,1部手机,请问先打印邮件还是短信?
class Phone {
public static synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
同样只要确认锁的是不是一个东西就知道会不会阻塞,调用sendEmail()时阻塞的是Phone class,调用sendSMS()时阻塞的是phone
输出结果
------sendSMS
------sendEmail
问题八:1个普通同步方法,1个静态同步方法,2部手机,请问先打印邮件还是短信?
class Phone {
public static synchronized void sendEmail() throws Exception {
try {
TimeUnit.SECONDS.sleep(4);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("------sendEmail");
}
public synchronized void sendSMS() throws Exception {
System.out.println("------sendSMS");
}
}
public class Lock8 {
public static void main(String[] args) throws Exception {
Phone phone = new Phone();
Phone phone1 = new Phone();
new Thread(()->{
try{
phone.sendEmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(()->{
try{
phone1.sendSMS();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
解题跟问题七一致,调用sendEmail()时阻塞的是Phone class,调用sendSMS()时阻塞的是phon1
输出结果
------sendSMS
------sendEmail