分析java基础知识点_JAVA基础知识点.md

## JAVA 三大特性

- 封装:**隐藏**对象的属性和实现**细节**,仅对外公开接口

- 继承: 子类继承父类的特征和行为,使得子类对象具有父类的属性和方法,使子类具体与父类相同的行为

- 多态:同一个接口,不同的实例有不同的实现,即父类的引用指向子类对象

## Synchorized和ReentryLock的区别

- Synchorized是一个关键字,存在于JVM层面,而ReentryLock依赖于API

- 两者都是可重入锁

- 加锁和解锁方面:Synchorized是通过进入/退出对象监视器来实现的,ReentryLock需要通过lock对象的lock加锁,并且在finally语句块中显示的释放,lock.unlock()

- ReentryLock的一些高级功能

- 等待可中断:在等待获取锁的时间内ReentryLock是可中断的,而Synchorized不可以

- **是否阻塞**:ReentryLock获取锁的过程是非阻塞的,Synchorized是阻塞的

- 可以实现公平锁(通过构造函数传入fair的值是ture或false可以控制是公平还是非公平)

- **等待通知机制的实现**:Synchorized通过对象的**wait()**和notify()来实现,而ReentryLock则使用Condition类来实现,通过lock.newCondition()来创建Condition对象,Condition可以实现选择性通知,更加灵活,**一个ReentryLock可以同时绑定多个condition对象**

- 性能:经过不断优化,Synchorized的性能和ReentryLock已经基本持平

## Synchorized和volatile的区别

- **作用域**

- volatile仅用于修饰变量

- Synchorized可作用于变量,方法,代码块,类

- volatile不保证**原子性**

- **是否阻塞**:volatile不会阻塞

- **虚拟机优化**:volatile不会被虚拟机优化(保证顺序性)

## 有关synchorized

- 会阻塞线程

- 不可中断

- 作用范围

- **性能**

### 同步问题

当多线程对类的**成员变量**进行修改时,多线程修改的是同一个变量。此时就会出现并发问题,而局部变量是线程私有的,不会出现线程安全问题

### synchorized的作用范围

- 修饰代码块

- 这段代码块称为静态代码块,作用范围是{}的部分,作用对象是调用这段代码块的对象

- 修饰普通方法

- 这个方法被称为同步方法,作用范围是整个方法,作用对象是调用这个方法的对象

- 修饰静态方法

- 修饰的是这个方法,作用对象是这个**类的所有对象**

- 修饰类

- 作用范围是synchorized(className.class)括号中的类,作用对象是括号中类的所有对象

总而言之:synchorized作用在方法还是对象上,如果对象是非静态的,那么锁的是对象,如果作用对象是静态或者是类的话,作用对象是类的所有对象,每个对象只有一个锁lock与之关联,谁拿到锁就可以运行它控制的那段代码,实现同步是要很大的系统开销作为代价的,甚至有可能造成死锁,所以要避免无用的同步

## 关于synchorized的优化

- **自旋锁**

- 线程状态之间状态转变需要很大的系统开销,在应用中,锁往往指存在很短的时间,自旋锁的思想是在一个线程请求锁的过程中执行忙循环(自旋)一段时间,如果在这段时间内能够获取锁,就可以避免进入阻塞状态,在1.6以后引入了适应性自旋,自旋的次数不再固定,由上一次的自旋次数以及锁的拥有者的状态来决定

- **锁消除**

- 将一些不会发生线程安全问题的所进行消除,例如String类

- **锁粗化**

- 将一些要对同一对象进行频繁加锁/解锁的操作,将锁的范围扩大到整个操作的外部,这样就只需要进行一次操作

- **偏向锁**

- 偏向锁的思想是偏向于第一个获取到锁的线程,这个线程在获取到锁之后再也不需要进行同步操作,甚至连CAS操作也不需要(**无争用的时候取消cas**)

- **轻量级锁**

- 从1.6以后锁有了四个状态:**无状态,偏向锁状态,轻量级锁状态和重量级锁状态**,轻量级锁的目的是避免重量级锁使用**互斥量**的开销,如果两条以上的线程同时竞争同一个锁,轻量级锁不再有用,将膨胀称为重量锁

## wait和sleep的区别

- **对象锁**

每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块。

sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!);

wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度);

wait()方法需要调用notify方法唤醒,唤醒以后才能参与对象锁的竞争

- 使用范围

sleep()方法可以在任何地方使用;

wait()方法则只能在同步方法或同步块中使用;(synchorized)

释放锁有两种方式:

(1)程序自然离开监视器的范围,即离开synchronized关键字管辖的代码范围

(2)在synchronized关键字管辖的代码内部调用监视器对象的wait()方法

- 不同类对象

sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;

wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态;

- 唤醒方式

在调用sleep()方法后,线程放弃cpu资源进入阻塞态,等时间片一到线程又进入就绪态

调用wait()方法后线程阻塞,直到调用对象的.notify()方法后才进入就绪状态

## String, String Builder 和String Buffer区别

**线程安全**:String Buffer

**快慢**:String Builder > String Buffer > String

String 慢的原因是:String为字符串常量(对String进行操作实际上是新创建了对象),而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的

适用范围:

- 少量字符串拼接:String

- 单线程下大量字符串拼接:String Builder

- 多线程下大量字符串拼接:String Buffer

## 接口和抽象类的区别,如何选择?

- 方法抽象:接口比抽象类还要抽象,接口中的方法全都是抽象方法,而抽象类中的方法不一定是抽象方法

- **方法类型**:抽象类可以是私有的,非abstract的,但是必须实现,接口中不能是私有的,默认是public abstract 类型

- 继承:一个类只可以继承一个抽象类,但是可以实现多个接口

- **成员变量类型**:接口中默认是public static final,不能重新定义

如何选择?

- 如果要实现**多重继承**,那么必须使用接口

- 如果基本功能在**不断改变**,那么需要抽象类,因为如果使用接口,那么接口定义也要变

## 反射的基本概念,反射是否可以调用私有方法

JAVA反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的**任意**属性和方法,并且能改变它的属性

反射是可以调用对象的私有方法的(只能调用自身,不能调用父类的),但是没有意义,破坏了JAVA的封装性

## JAVA8的新特性

- Lambda表达式

- 接口中可以有一个默认的实现方法,使用default关键字修饰

- Stream API,支持**函数式编程**

- Date Time API:加强对时间日期的处理

- Optinal类:用于解决空指针异常

- 新的JavaScript引擎

## finally语句是在什么时候执行的

- finally是在**return 语句之后,返回结果之前执行**的,先将return 的结果保存,所以函数的返回值是在finally之前就已经确定了

- finally中如果有return,则函数是在这里返回

- 无论如何finally都会执行,即使发生异常

## String不可变的原因

- String 类用final关键字修饰,所以不可被继承,不可被改变

- 内部使用char[]保存值,这个数组使用private final进行修饰,final保证char[]引用不变(因为数据还是可以改变的,数组引用是在栈上,但是数组元素是保存在堆上),private保证char[]不被暴露,所以内容也不可变

## String不可变的好处

- **线程安全**,final保证了线程安全,例如hashmap的key,或是string经常被作为参数传递

- 维护一个**字符串常量池**,不需要重复创建,节省时间和空间

## 同步和异步的区别

- 同步:一个线程在发起调用时,必须等待执行结果,在没有得到结果之前,不能进行后序操作

- 异步:发起调用之后,没有得到结果,调用者可以进行后序操作,一般调用结果是通过状态,通知,回调的方式通知调用者

一键复制

编辑

Web IDE

原始数据

按行查看

历史

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值