1、 介绍一下Syncronized 锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?

synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证它修饰的方法或者代码块在任意时刻只能有一个线程执行。

synchronized 关键字加到static静态方法和synchronized(class)代码块上都是给Class类上锁。

synchronized关键字加到实例方法上是给对象实例上锁。


2、 volatile关键字

volatile 关键字是用来保证有序性和可见性的

volatile 变量规则
对一个变量的写操作先行发生于后面对这个变量的读操作;
有序性:实现是通过插入内存屏障来保证的。
可见性:首先Java 内存模型分为,主内存,工作内存。比如线程A 从主内存把变量从主内存读到了自己的工作内存中,做了加1 的操作,但是此时没有将i 的最新值刷新会主内存中,线程B 此时读到的还是i 的旧值。加了volatile 关键字的代码生成的汇编代码发现,会多出一个lock 前缀指令。Lock 指令对Intel平台的CPU,早期是锁总线,这样代价太高了,后面提出了缓存一致协性议,MESI,来保证了多核之间数据不一致性问题。

2.1、并发编程的三个重要性

1、原子性:一次操作或者多次操作,要么所有的操作都得到执行并且不会受到任何因素的干扰而中断,要么所有的操作都执行,要么都不执行。synchronized可以保证代码片段的原子性。

2、可见性:当一个变量对共享变量进行了修改,那么另外的线程都是立即可以看到修改后的最新值。volatile关键字可以保证共享变量的可见性。

3、有序性:代码在执行的过程中的先后顺序,java在编译器以及运行期间的优化,代码的执行顺序未必就是编写代码时候的顺序。volatile关键字可以禁止指令进行重排序优化。

2.2 、synchronized关键字和volatile关键字的区别

1、 volatile关键字是线程同步的轻量级实现,所以volatile性能比synchronized关键字好。
但是volatile关键字只能用于变量,而synchronized关键字可以修饰方法以及代码块。

2、多线程访问volatile关键字不会发送阻塞,而synchronized关键字可能会发生阻塞

3、volatile关键字能保证数据的可见性,但不能保证数据的原子性。
synchronized关键字两者都能保证

4、volatile关键字主要用于解决变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间的访问资源的同步性

2.3、关于锁,说一下Synchronized 和lock

synchronized 是Java 的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。JDK1.5 以后引入了自旋锁、锁粗化、轻量级锁,偏向锁来有优化关键字的性能。

Synchronized 和lock的区别

1、Lock 是一个接口,而synchronized 是Java 中的关键字,synchronized 是内置的语言实现;

2、synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;
   Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象。因此使用Lock时需要在finally 块中释放锁;

3、Lock 可以让等待锁的线程响应中断,而synchronized 却不行,使用synchronized 时,等待的线程会一直等待下去,不能够响应中断

4、通过Lock 可以知道有没
有成功获取锁,而synchronized 却无法办到。


3、 final 关键字怎么用

作用
1、修饰变量,变量的引用地址不可变,但是地址中的内容可以变
2、修饰方法,方法不可被重写,但是还是可以重载
3、修饰类,类不可继承

final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。

1、修饰类
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。

2、修饰方法
“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。“

因此,如果只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final的。

3、修饰变量
修饰变量是final用得最多的地方

对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象但该引用所指向的对象的内容是可以发生变化的

3.1、final和static

static作用于成员变量用来表示只保存一份副本,而final的作用是用来保证变量不可变


4、static关键字

4.1、static用途

static对象可以在它的任何对象创建之前访问,无需引用任何对象。

就是在调用类的成员变量或方法时,可以直接使用类名.方法名,而无需再去使用new一个类,然后再使用对象引用来调用,使用起来更便捷。而用static修饰的成员变量和方法跟上述类似。故使用static提高了共享性。

非static方法必须等对象被new出来以后才能使用,因而不能在main中直接调用。

static主要是减少成员变量和方法的多次创建,一旦声明为静态,该成员变量或方法就属于这个类,可以被该类所创建的所有对象共享,就能直接用类名来调用

4.2、静态内部类 和 成员类的区别

(1)内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用

(2)非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。

(3)一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

4.3、静态变量

static修饰的属性,称为类属性,即全局变量。前面已经有提及。

(1).静态变量可以使用类名直接访问,也可以使用对象名进行访问。

 class Number
  {
      int a;
     static int b;
  }
  public class T01
  {
      public static void main(String[] args)
      {
         Number.a=5;//错误的
         Number.b=6;//正确的,b是static修饰的静态变量可以直接用类名调用
     }
 }

(2).static不允许修饰局部变量:

public static void max(int a,int b)
 {
        static int result;//Java中不被允许   
}

(3).非静态和静态方法中均可以访问static变量。

按照是否静态的对类成员变量进行分类可分两种:一种是被static修饰的变量,叫静态变量或类变量;另一种是没有被static修饰的变量,叫实例变量。

两者的区别是:

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

所以一般在需要实现以下两个功能时使用静态变量: - 在对象之间共享值时 - 方便访问变量时

4.4、静态方法

static修饰的方法,称为类方法。

(1).静态方法中可以调用类中的静态变量,但不能调用非静态变量。

 class Number
  {
      int a;
      static int b;
      public static void max(int c,int d)
        {
             int result;
             result=a+b;//a是非静态变量不能被静态方法直接调用

       }
 }

(2).static方法没有this—不依附于任何对象。

  class Person
 {
     static String name;
     static int age;
     public static void print(String n,int a)
     {
         this.name=n;//错误的,静态方法中无法使用this
         age=a;
     }
 }

静态方法可以直接通过类名调用,任何的实例也都可以调用, 因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。 因为实例成员与特定的对象关联!!

因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。

4.5、静态初始化块

类加载时执行,且只会执行一次,只能给静态变量赋值,不能接受任何参数。

static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次

  class Number
  {
     static int a;
     static int b;
     public static void print()
     {
         int result;
         result=a+b;
         System.out.println(result);
     }
     static//static语句块用于初始化static变量,是最先运行的语句块
     {
         a=5;
         b=8;
     }
 }
 public class T01{
     public static void main(String[] args){
         Number.print();
     }
 }

因为static语句块只会在类加载时执行一次的特性,经常用来优化程序性能。


5、this

代表当前对象,封装对象属性

1.使用this调用本类中的成员变量。

public void setName(String name)
{
     this.name=name;//类似于指针的作用
}

2.当成员变量和方法中的局部变量名字相同时,使用this调用成员变量。

3.this在方法内部调用本类中的其他方法。

 class Person
 {
     int age;
     public void setAge(int age)
     {
          this.age=age;
          this.print();//调用本类中的print()方法
     }
     public int getAge()
     {
         return age;
     }
     public void print()
     {
         System.out.println("我今年是:"+age+"岁");
     }
 }
 public class T01
 {
     public static void main(String[] args)
     {
         Person p = new Person();
         p.setAge(12);
     }
 }

4.this在方法中调用类的构造函数,必须位于第一行。


6、super

super关键字用于从子类访问父类的变量和方法。 例如:

public class Super {
    protected int number;

    protected showNumber() {
        System.out.println("number = " + number);
    }
}

public class Sub extends Super {
    void bar() {
        super.number = 10;
        super.showNumber();
    }
}

在上面的例子中,Sub 类访问父类成员变量 number 并调用其其父类 Super 的 showNumber()方法

使用 this 和 super 要注意的问题:

1、在构造器中使用 super()调用父类中的其他构造方法时,该语句必须处于构造器的首行,否则编译器会报错。另外,this调用本类中的其他构造方法时,也要放在首行。

2、this、super不能用在static方法中。