天天看点

Java笔记

1、继承Thread类,重写run()方法,new一个实例对象,调用start()方法;

2、实现Runnable接口,重写run()方法,new一个实例对象,作为Thread的target来创建;

3、实现Callable接口

初生、就绪、运行、阻塞、消亡

重载是对类中同名方法采取的操作,通过改变形参数量、类型、顺序,使得同一方法可以有不同的传参形式

重写是子类对父类中同名方法的替换,返回值,方法名,参数类型必须一致,可以实现多态。

重写遵循"两同两小一大"

方法名、形参相同

返回值、抛出异常更小

权限修饰符更大

封装:限制用户对类的访问,只暴露必要的接口给用户,可以减少用户的误操作,方便开发者对内部细节的调整和迭代

继承:实现对类的拓展,减少重复代码。私有属性和方法子类无法访问

多态:实现接口或重写父类方法,程序运行时才决定实际调用的方法

String底层是用final修饰的数组,视为常量,不可变

StringBuffer底层的方法用sychonized锁,线程安全

StringBuild线程不安全

抽象类更像模板,可以有非抽象方法

接口更像行为规范,只能有抽象方法和static final变量

基本数据类型比较值,引用数据类型比较内存地址

equals未重写,与==相同,重写后一般比较对象内的值

重写equals必须重写hashcode 否则类的两个实例对象一定不会相等

只能修饰变量,不能修饰类和方法,阻止变量序列化

arrayList线程不安全,效率高

Vector线程安全,效率低

HashMap线程不安全效率高

HashTable线程安全效率低

HashMap支持nullkey nullvalue HashTable会报异常

HashMap的大小为2的幂次方,每次扩容翻倍,底层是数组+链表+红黑树,链表长度大于8时,如果数组长度大于64,链表会转换成红黑树,否则进行数组扩容

计算HashCode,不同直接加入,相同进行equals比较

JDK1.7 使用segment,分段锁,操作数据先获取对应的segment锁,效率比HashTable全表锁高

JDK1.8 数据结构和HashMap一致,改为synchronized,只锁链表或红黑树的首节点,效率进一步提高

线程是轻量级进程,线程共享统一进程的堆和方法区,每个线程有自己的程序计数器、本地方法栈、虚拟机栈

调用start方法线程进入就绪状态,等待cpu分配时间片,是真正的多线程

调用run方法会直接执行该方法,还是在当前线程

第一次判断null是为了快速返回单例对象,就像先比较hash在进行equals

第二次判断null + synchronized 是为了确保单例

volatile保证了有序性,防止指令重排

因为 singleton = new Singleton() 这句话可以分为三步:

1. 为 singleton 分配内存空间;

2. 初始化 singleton;

3. 将 singleton 指向分配的内存空间。

但是由于JVM具有指令重排的特性,执行顺序有可能变成 1-3-2。 指令重排在单线程下不会出现问题,但是在多线程下会导致一个线程获得一个未初始化的实例。例如:线程T1执行了1和3,此时T2调用 getInstance() 后发现 singleton 不为空,因此返回 singleton, 但是此时的 singleton 还没有被初始化。

使用 volatile 会禁止JVM指令重排,从而保证在多线程下也能正常执行。

线程的创建和销毁都需要消耗资源,比如内存空间,时间等

线程池可以重复利用已创建的线程,减少资源消耗

线程不需要创建,拿来即用,提高响应速度

线程池管理线程,保证线程不滥用,避免线程创建过多

Runnable不返回结果和抛出异常,更加简洁

上一篇: jdk安装

继续阅读