翻车现场一:由synchronized的使用场景引发 static和this关键字你真的了解吗

前言

我们在开发的时候往往会忽略java知识的一些细节使用,但是这些细节点往往是面试的时候比较关注的,下面总结下面试过程中容易翻车的一些细节点,供大家参考。

synchronized的使用场景可以归结为3种:

① 修饰静态方法,给当前类对象加锁,进入同步方法时需要获得类对象的锁
② 修饰实例方法,给当前实例变量加锁,进入同步方法时需要获得当前实例的锁
③ 修饰同步方法块,指定加锁对象(可以是实例对象,也可以是类变量),对给定对象加锁,进入同步方法块时需要获得加锁对象的锁

1、静态方法

Class BankAccount{
      private static int accountNum; // 一共有多少个银行账号
      
      public static synchronized void setAccountNum(){
                accountNum = accountNum + 1;
      }
}

2、成员方法

public class BankAccount{
        private double balance;
        private static Logger logger = LoggerFactory.getLogger(BankAccount.class);

        public synchronized void deposite(double moneyToAdd){
                String threadName = Thread.currentThread().getName();
                logger.info(threadName + "--当前银行余额为:" + this.balance);
                balance = balance + moneyToAdd;
                logger.info(threadName + "--存后银行余额为:" + this.balance);
        }
}

3、同步代码块,块对象是实例对象

public class BankAccount{
        private double balance;
        private static Logger logger = LoggerFactory.getLogger(BankAccount.class);

        public void deposite(double moneyToAdd){
                String threadName = Thread.currentThread().getName();
                logger.info(threadName + "--当前银行余额为:" + this.balance);
                synchronized(this){
                      balance = balance + moneyToAdd;
                }
                logger.info(threadName + "--存后银行余额为:" + this.balance);
        }
}

4、同步代码块,块对象是类对象

Class BankAccount{
      private static int accountNum; // 一共有多少个银行账号
      
      public synchronized void setAccountNum(){
          synchronized(BankAccount.class){
                 accountNum = accountNum + 1;
          }  
      }
}

synchronized 修饰在 static方法和非static方法的区别

static的方法属于类方法,它属于这个Class(注意:这里的Class不是指Class的某个具体对象),那么static获取到的锁,是属于类的锁。而非static方法获取到的锁,是属于当前对象的锁。所以,他们之间不会产生互斥。

public class Aa{
static synchronized void bb(){}
static synchronized void cc(){}
}

当两个线程同时分别访问 bb 和 cc 方法时,此时只有bb方法执行完毕,才会执行cc。

静态变量

  • 一种是被static修饰的变量,叫静态变量或类变量
  • ​​​另一种是没有被static修饰的变量,叫实例变量

两者的区别是:
   对于静态变量在内存中只有一个(节省内存),JVM只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。
    对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。

静态方法

  • 非静态方法既可以访问静态数据成员又可以访问非静态数据成员,而静态方法只能访问静态数据成员; 
  • 非静态方法既可以访问静态数据方法又可以访问非静态数据方法,而静态方法只能访问静态数据方法。 

原因:因为静态方法和静态数据成员会随着类的定义而被分配和装载入内中;而非静态方法和非静态数据成员只有在类的对象创建时在对象的内存中才有这个方法的代码段。此时还不存在内存中,所以不能调用。

静态代码块

那什么是静态代码块呢?说白了,静态代码块就是用static修饰的代码块  特点:随着类的加载而执行,而且只执行一次

static方法中不能使用this

Static方法是类方法,先于任何的实例(对象)存在。即Static方法在类加载时就已经存在了,但是对象是在创建时才在内存中生成。而this指代的是当前的对象 在方法中定义使用的this关键字,它的值是当前对象的引用.被static修饰的成员变量和成员方法独立于该类的任何对象。static表示不要实例化就可以使用。

this关键字

Java提供了一个this关键字,this关键字总是指向调用该方法的对象。根据this出现的位置的不同,this作为对象的默认引用有两种情形。

  1. 构造器中引用该构造器正在初始化的对象。
  2. 在方法中引用调用该方法的对象。

this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的类型只能是当前类:只有当这个方法被调用时,它所代表的对象才被确定下来:谁在调用这个方法,this就代表谁。

//定义一个eat()方法,eat()方法需要借助move()方法
public void eat(){
    //使用this引用调用eat()方法的对象
    this.move();
    System.out.println("正在执行eat()方法");
}

翻车现场一:由synchronized的使用场景引发 static和this关键字你真的了解吗_第1张图片

你可能感兴趣的:(Java进阶)