Java基础

  1. 解释下什么是面向对象?面向对象和面向过程的区别?

    面向对象是一种思想,世间万物都可以看做一个对象,对象作为系统开发的单位,而不是每一步的实现过程。

    1. 面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
    2. 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
    3. 面向对象是以功能来划分问题,而不是步骤.
  2. 面向对象的三大特性?分别解释下?

    封装,给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。
    继承,给对象提供了从基类获取字段和方法的能力。
    多态,是编程语言给不同的底层数据类型做相同的接口展示的一种能力。
    抽象,是把想法从具体的实例中分离出来的步骤。

  3. 重载和重写的区别?

    重载发生在同一个类中:
    1)、必须具有不同的参数列表,参数类型或者参数个数不同;
    2)、可以有不同的返回类型,只要参数列表不同就可以了;
    3)、可以有不同的访问修饰符;
    4)、可以抛出不同的异常;
    重写发生继承中,子类重写父类的方法,方法名和参数类型相同,内部实现可以不同,访问修饰符的限制一定要大于被重写方法的访问修饰符,重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。

  4. Java 中是否可以重写一个 private 或者 static 方法?

    Java 中 static ⽅法不能被覆盖,因为⽅法覆盖是基于运⾏时动态绑定的,⽽ static ⽅法是编译时静态绑定的。
    static ⽅法跟类的任何实例都不相关,所以概念上不适⽤。
    Java 中也不可以覆盖 private 的⽅法,因为 private 修饰的变量和⽅法只能在当前类中使⽤, 如果是其他的类继承
    当前类是不能访问到 private 变量或⽅法的,当然也不能覆盖。

  5. 构造方法有哪些特性?

    1.名字与类名相同。
    2.没有返回值,但不能用 void 声明构造函数。
    3.生成类的对象时自动执行,无需调用。
    4.默认有无参构造器,重载构造器要显式的声明出无参构造器。

  6. 在 Java 中定义一个不做事且没有参数的构造方法有什么作用?

    子类实例化对象时,必定会调用自己的构造方法,在自己的构造方法中又必定会调用父类的构造方法(super())(默认调用父类的无参构造方法)
    如果父类没有任何构造方法,那么不会报编译上的错误,因为系统会赠送父类一个无参构造方法,但如果父类有带参数的构造方法,那么系统不会赠送父类无参构造方法了,那么子类中如果没有使用super()调用父类的有参构造方法,会报编译上的错误,解决方法是在父类显式声明一个无参构造方法。
    作用:让子类继承父类的时候能够默认调用无参构造方法顺利实例化父类对象,而不至于产生编译上的错误。

  7. Java 中创建对象的几种方式?

    -  new关键字new Person();
    -   Class.newInstance  (反射机制,必须有public的无参构造器才行)   Person person = Person.class.newInstance();
    -   Constructor.newInstancejava.lang.relect.Constructor类里也有一个newInstance方法可以创建对象。可以通过这个newInstance方法调用有参数的和私有的构造函数。// 包括public的和非public的,当然也包括private的Constructor<?>[] declaredConstructors = Person.class.getDeclaredConstructors();// 只返回public的~~~~~~(返回结果是上面的子集)Constructor<?>[] constructors = Person.class.getConstructors();Constructor<?> noArgsConstructor = declaredConstructors[0];Constructor<?> haveArgsConstructor = declaredConstructors[1];noArgsConstructor.setAccessible(true); // 非public的构造必须设置true才能用于创建实例Object person1 = noArgsConstructor.newInstance();Object person2 = declaredConstructors[1].newInstance("fsx", 18);
    -   Clone方法(clone方法创建对象并不会调用任何构造函数)必须先实现Cloneable接口,复写Object的clone方法public class Person implements Cloneable {// 访问权限写为public,并且返回值写为person@Overridepublic Person clone() throws CloneNotSupportedException {return (Person) super.clone();}}public class Main {public static void main(String[] args) throws Exception {Person person = new Person("fsx", 18);Object clone = person.clone();System.out.println(person);System.out.println(clone);System.out.println(person == clone); //false}}      反序列化  (序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。)实现 Serializable接口Person person = new Person("fsx", 18);byte[] bytes = SerializationUtils.serialize(person);// 字节数组:可以来自网络、可以来自文件(本处直接本地模拟)Object deserPerson = SerializationUtils.deserialize(bytes);
    
  8. 静态变量和实例变量的区别?

    实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
    静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了
    
  9. short s1 = 1;s1 = s1 + 1;有什么错?那么 short s1 = 1; s1 += 1;呢?有没有错误?

    s1+1运算时会自动提升表达式的类型为int,那么将int赋予给short类型的变量s1会出现类型转换错误。

  10. Integer 和 int 的区别?

    1、Integer是int的包装类,int则是java的一种基本数据类型
    2、Integer变量必须实例化后才能使用,而int变量不需要
    3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
    4、Integer的默认值是null,int的默认值是0
    5.Integer变量和int变量比较时,只要两个变量的值是向等的,则结果为true(因为包装类Integer和基本数据类型int比较时,java会自动拆包装为int,然后进行比较,实际上就变为两个int变量的比较)
    6.非new生成的Integer变量和new Integer()生成的变量比较时,结果为false。(因为非new生成的Integer变量指向的是java常量池中的对象,而new Integer()生成的变量指向堆中新建的对象,
    7.对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false。
    public static Integer valueOf(int i){assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high){return IntegerCache.cache[i + (-IntegerCache.low)];
    }
    return new Integer(i);
    }
    
  11. 装箱和拆箱的区别

    装箱就是  自动将基本数据类型转换为包装器类型;拆箱就是  自动将包装器类型转换为基本数据类型。
    在装箱的时候自动调用的是Integer的valueOf(int)方法。而在拆箱的时候自动调用的是Integer的intValue方法。
    
  12. switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?

    • switch可作用于char byte short int
    • switch可作用于char byte short int对应的包装类
    • switch不可作用于long double float boolean,包括他们的包装类
    • switch中可以是字符串类型,String(jdk1.7之后才可以作用在string上)
    • switch中可以是枚举类型
  13. final、finally、finalize 的区别?

    1.简单区别:
    final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。
    finally是异常处理语句结构的一部分,表示总是执行。
    finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。
    2.中等区别:
    final:java中的关键字,修饰符。A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声 明为abstract抽象类的和final的类。
    B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
    1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
       2)被声明final的方法只能使用,不能重载。
    finally:java的一种异常处理机制。
       finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
    finalize:Java中的一个方法名。
    Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

  14. == 和 equals 的区别?

    ==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向的内存空间的值是不是相同
    ==是指对内存地址进行比较 , equals()是对字符串的内容进行比较
    ==指引用(地址)是否相同,equals()指的是值是否相同
    
  15. 两个对象的 hashCode() 相同,则 equals() 也一定为 true 吗?

    两个对象equals相等,则它们的hashcode必须相等,反之则不一定。
    两个对象==相等,则其hashcode一定相等,反之不一定成立。
    
  16. 为什么重写 equals() 就一定要重写 hashCode() 方法?

    【强制】关于 hashCode 和 equals 的处理,遵循如下规则: 1) 只要重写 equals,就必须重写 hashCode。 2) 因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的 对象必须重写这两个方法。 3) 如果自定义对象作为 Map 的键,那么必须重写 hashCode 和 equals。 说明:String 重写了 hashCode 和 equals 方法,所以我们可以非常愉快地使用 String 对象 作为 key 来使用。
    原因:如果不重写hashCode方法,则会发生两个相同的对象出现在HashSet,HashMap集合中,两个相同的key出现在Map中,这是不被允许的,综上所述,在日常的开发中,只要重写了equals方法,就必须重写hashCode。
    HashSet和HashMap底层put时使用了HashCode(),如果不重写HashCode(),将会导致两个相同的对象都会作为key存入,导致重复。
    
  17. & 和 && 的区别?

    &: 按位与
    &&:逻辑与
    
  18. Java 中的参数传递时传值呢?还是传引用?

    值传递,对于对象的传递,实质上也是拷贝的对象地址的值,而不是引用。

  19. Java 中的 Math.round(-1.5) 等于多少?

    -1 四舍五入
    //四舍六入五成双
    //当有效位数确定后,其后面多余的数字应该舍去,只保留有效数字最末一位,这种修约(舍入)规则是“四舍六入五成双”,也即“4舍6入5凑偶”这里“四”是指≤4 时舍去,”六”是指≥6时进上,”五”指的是根据5后面的数字来定,当5后有数时,舍5入1;当5后无有效数字时,需要分两种情况来讲:①5前为奇数,舍5入1;②5前为偶数,舍5不进。(0是偶数)
    
  20. 如何实现对象的克隆?

    实现 Cloneable 接口,重写 clone() 方法。
    不实现 Cloneable 接口,会报 CloneNotSupportedException 异常。
    
  21. 深克隆和浅克隆的区别?

    Object 的 clone() 方法是浅拷贝,即如果类中属性有自定义引用类型,只拷贝引用,不拷贝引用指向的对象。
    深拷贝:对象的属性的Class 也实现 Cloneable 接口,在克隆对象时也手动克隆属性。
    结合序列化(JDK java.io.Serializable 接口、JSON格式、XML格式等),完成深拷贝
    
  22. 什么是 Java 的序列化,如何实现 Java 的序列化?

    当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。前者为序列化,后者为反序列化。
    java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。只有实现了Serializable和Externalizable接口的类的对象才能被序列化。java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
    
  23. 什么情况下需要序列化?

    当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。
    `transient` 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 `transient` 修饰的变量值不会被持久化和恢复。
    
  24. Java 的泛型是如何工作的 ? 什么是类型擦除 ?

    泛型通过类型擦除来将变量变为一个类型,编译器在编译时擦出了所有类型相关的信息,所以在运行时不存在任何类型相关的信息,例如 List <String> 在运行时仅以 List 来表示;
    这样做可以确保能和 Java 5 之前的版本开发二进制类库兼容;
    无法在运行时访问到数据类型,因为编译器已经把泛型类型转换成了原始类型;
    
  25. 什么是泛型中的限定通配符和非限定通配符 ?

    一种是它通过确保类型必须是T的子类来设定类型的上界,另一种是它通过确保类型必须是T的父类来设定类型的下界。1. 表示类型的上界,格式为:<? extends T>,即类型必须为T类型或者T子类2. 表示类型的下界,格式为:<? super T>,即类型必须为T类型或者T的父类3. 非限定通配符:类型为<T>,可以用任意类型来替代。
    
  26. List 和 List 之间有什么区别 ?

    List、List<?>、List<Object>的区别List,即原始类型,其引用变量可以接受任何对应List<E>的参数化类型, 包括List<?>,并且可以添加任意类型的元素。但其缺点在于不安全性、不便利性、不表述性(不应该使用原生类型的原因)。List<?>,即通配符类型,其引用变量,同样可以接受任何对应List<E>的参数化类型,包括List,但不能添加任何元素,保证了安全性和表述性。但不具有表述性,从中取出的元素时Object类型,要通过手动转换才能得到原本的类型。List<Object>,即实际类型参数为Object的参数化类型,其引用变量可以接受List,可以添加元素,但不能接受除了其本身外的任何参数化类型(泛型的子类型化原则)。
    
  27. Java 中的反射是什么意思?有哪些应用场景?

    //反射机制介绍
    JAVA 反射机制是在*运行状态*中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种 //动态获取的信息以及动态调用对象的方法的功能// 称为 java 语言的反射机制。
    //获取Class对象的两种方式
    知道具体类的情况下可以使用:Class alunbarClass = TargetObject.class;
    通过 Class.forName()传入类的路径获取:Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
    //应用:反射是框架设计的灵魂JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序Spring 框架的 IOC(动态加载管理 Bean)创建对象以及 AOP(动态代理)功能都和反射有联系动态配置实例的属性
    
  28. 反射的优缺点?

    优点: 运行期类型的判断,动态加载类,提高代码灵活度。
    缺点: 1,性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。
    
  29. Java 中的动态代理是什么?有哪些应用?

    动态代理:在运行时,创建目标类,可以调用和扩展目标类的方法。
    Java 中实现动态的方式:JDK 中的动态代理 和 Java类库 CGLib。
    //应用场景如:统计每个 api 的请求耗时统一的日志输出校验被调用的 api 是否已经登录和权限鉴定Spring的 AOP 功能模块就是采用动态代理的机制来实现切面编程
    

  30. 怎么实现动态代理?

    //动态代理的实现
    使用的模式:代理模式。
    代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。类似租房的中介。
    //两种动态代理:(1)jdk动态代理,jdk动态代理是由Java内部的反射机制来实现的,目标类基于统一的接口(InvocationHandler)(2)cglib动态代理,cglib动态代理底层则是借助asm来实现的,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。//主要应用的框架:Spring中的AOP,Struts2中的拦截器
    
  31. static 关键字的作用?

    static 标志类成员变量,类方法,静态代码块,这些都是在类加载的时候便会为其分配空间,不需要实例出对象就可以调用其方法和属性。
    static 块可以优化程序性能,是因为它的特性:只会在类被初次加载的时候执行一次
    
  32. super 关键字的作用?

    1.super关键字可以在子类的构造方法中显示地调用父类的构造方法,super()必须为子类构造函数中的第一行。
    2.super可以用来访问父类的成员方法或变量,当子类成员变量或方法与父类有相同的名字时也会覆盖父类的成员变量或方法,这个时候要想访问父类的成员变量或方法只能通过super关键字来访问,子类方法中的super.方法名()不需要位于第一行。
    
  33. 字节和字符的区别?

    位数不同,Java 字节占8 bit,Java字符占两字节。

  34. String 为什么要设计为不可变类?

    //常量池的需要
    这个方面很好理解,Java 中的字符串常量池的存在就是为了性能优化。字符串常量池(String pool)是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串已经存在于常量池中,则不会创建新的对象,而是直接引用已经存在的对象。这样做能够减少 JVM 的内存开销,提高效率。
    //hashcode 缓存的需要
    因为字符串不可变,所以在它创建的时候 hashcode 就被缓存了,不需要重新计算。这就使得字符串很适合作为 HashMap 中的 key,效率大大提高。
    //多线程安全
    多线程中,可变对象的值很可能被其他线程改变,造成不可预期的结果。而不可变的 String 可以自由在多个线程之间共享,不需要同步处理。
    //如何实现不可变:
    私有成员变量;
    Public 的方法都是复制一份数据;
    String 是 final 的;
    构造函数深拷贝;
    public String(char value[]) {this.value = Arrays.copyOf(value, value.length);//而非this.value = value;
    }
    
  35. String、StringBuilder、StringBuffer 的区别?

    String 是 final修饰的,不可变,每次操作都是生成新的String对象 ==》浪费内存
    StringBuffer(线程安全) StringBuilder(线程不安全) ,二者都是在原对象上进行操作的
    性能: StringBuilder > StringBuffer > String
    场景: 需要经常改变字符串时使用后两个,优先使用 StringBuilder,多线程共享变量时使用 StringBuffer;
    
  36. String 字符串修改实现的原理?

    String a = "a";——>发现常量池中没有"a",在常量池中创建①"a";
    String b = "b";——>发现常量池中没有"b",在常量池中创建②"b";
    String c = "ab";——>发现常量池中没有"ab",在常量池中创建③"ab";
    String d = "a" + "b";——>发现常量池中有"a"——>发现常量池中有"b"——>"a" + "b" = "ab"——>发现常量池中有"ab";
    String f = "ab" + "c";——>发现常量池中有"ab"——>发现常量池中没有"c",在常量池中创建④"c";——>"ab" + "c" = "abc",发现常量池中没有"abc",在常量池中创建⑤"abc";
    String g = "abc";——>发现常量池中有"abc";
    String h = "a" + "c" +"b";——>发现常量池中有"a"——>发现常量池中有"c"——>发现常量池中有"b"—— >"a" + "c" = "ac",发现常量池中没有"ac",在常量池中创建⑥"ac";——> "ac" + "b" = "acb";——>发现常量池中没有"acb",在常量池中创建⑦"acb";
    
  37. String str = “i” 与 String str = new String(“i”) 一样吗?

    内存的分配方式不一样。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”)方式,则会被分到堆内存中。
    堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。
    
  38. String 类的常用方法都有那些?

    length()、charAt()、substring()、compareTo()、equals()、concat()、indexOf()、lastIndexOf()
    
  39. final 修饰 StringBuffer 后还可以 append 吗?

    可以。. final 修饰的是一个引用变量,那么这个引用始终只能指向这个对象,但是这个对象内部的属性是可以变化的.
    //同是final修饰,为什么StringBuffer可变,但是String不可变?
    String不可变是说String中用一个final 的char数组 private final char value[]; 保存字符序列。用final修饰的对象值可变,但是引用不变,即:value指向不可变,但是value[]数组的值可变,但因为有  private 关键字对其进行封装达到 value[] 数组值也不可变的目的。
    
  40. Java 中的 IO 流的分类?说出几个你熟悉的实现类?

    //按流向分类:输入流输出流
    //按处理数据不同分类:字节流:二进制,可以处理一切文件,包括:纯文本、doc、音频、视频等。字符流:文本文件,只能处理纯文本。
    //按功能不同分类:节点流:包裹源头。处理流:增强功能,提高性能。
    File,inputStream,OutputStream,Reader和Writer
    
  41. 字节流和字符流有什么区别?

    字符流使用了缓冲区(不关闭流缓冲区的数据默认不会输出),而字节流没有使用缓冲区。
    
  42. BIO、NIO、AIO 有什么区别?

    BIO:线程发起IO请求,不管内核是否准备好IO操作,从发起请求起,线程一直阻塞,直到操作完成。
    NIO:线程发起IO请求,立即返回;内核在做好IO操作的准备之后,通过调用注册的回调函数通知线程做IO操作,线程开始阻塞,直到操作完成。
    AIO:线程发起IO请求,立即返回;内存做好IO操作的准备之后,做IO操作,直到操作完成或者失败,通过调用注册的回调函数通知线程做IO操作完成或者失败。
    BIO是一个连接一个线程。
    NIO是一个请求一个线程。
    AIO是一个有效请求一个线程。
    BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
    NIO:同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
    AIO:异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
    

Java异常

finally 块中的代码什么时候被执行?

 //try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗? 会如果在try{} 语句块中有return语句,finally语句块中没有return语句,finally语句块中的代码在return语句前执行。当 try{} 和 finally{} 中都存在return语句块,finally语句块中的return语句会覆盖其他return语句;//finally语句一定会执行吗?不一定当程序进入try语句之前就出现异常时,会直接结束,不会执行finally语句块中的语句代码。即没有进入语句块时。
当程序在try语句块中强制退出时也不会执行finally语句块中的代码;

Error和Exception区别

 Exception 和 Error 都是继承了 Throwable 类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。Error是指在正常情况下,不大可能出现的情况,绝大部分的 Error都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如 OutOfMemoryError 之类,都是 Error 的子类。

 // NoClassDefFoundError 和 ClassNotFoundException 区别当应用程序运行的过程中尝试使用类加载器去加载Class文件的时候,如果没有在classpath中查找到指定的类,就会抛出ClassNotFoundException。一般情况下,当我们使用Class.forName() 或者ClassLoader.loadClass以及使用ClassLoader.findSystemClass()在运行时加载类的时候,如果类没有被找到,那么就会导致JVM抛出ClassNotFoundException;NoClassDefFoundError异常,看命名后缀是一个Error。从类继承层次上看,NoClassDefFoundError是从Error继承的; 当JVM在加载一个类的时候,如果这个类在编译时是可用的,但是在运行时找不到这个类的定义的时候,JVM就会抛出一个NoClassDefFoundError错误。比如当我们在new一个类的实例的时候,如果在运行是类找不到,则会抛出一个NoClassDefFoundError的错误(编译后删除Class文件再执行就会报错);

运行时异常和受检查异常的区别

1. 所有的异常都集成自java.lang.Throwable,它有两个直接的子类:Error、Exception.
2. Error错误:JVM内部出现的严重问题,无法恢复;
3. Exception异常:普通的问题。通过合理的处理,程序还可以回到正常执行流程。要求编程人员要进行处理;
4. RuntimeException:也叫非受检异常(unchecked exception).这类异常是编程人员的逻辑问题。应该承担责任。Java编译器不进行强制要求处理。 也就是说,这类异常再程序中,可以进行处理,也可以不处理;
5. 受检异常(checked exception):这类异常是由一些外部的偶然因素所引起的。Java编译器强制要求处理。也就是说,程序必须进行对这类异常进行处理。
6. 非受检异常:NullPointerException,ClassCastException,ArrayIndexsOutOfBoundsException,ArithmeticException(算术异常,如除0溢出)
7. 受检异常:Exception,FileNotFoundException,IOException,SQLException。

throw 和 throws 的区别?

1. 当一个方法产生一个它不处理的异常时,那么就需要在该方法的头部声明这个异常,以便将该异常传递到方法的外部进行处理。使用 throws 声明的方法表示此方法不处理异常(方法调用者处理)
2. 与 throws 不同的是,throw 语句用来直接拋出一个异常,后接一个可拋出的异常类对象
3. 当 throw 语句执行时,它后面的语句将不执行,此时程序转向调用者程序,寻找与之相匹配的 catch 语句,执行相应的异常处理程序。如果没有找到相匹配的 catch 语句,则再转向上一层的调用程序。这样逐层向上,直到最外层的异常处理程序终止程序并打印出调用栈情况。
4. throws 用来声明一个方法可能抛出的所有异常信息,表示出现异常的一种可能性,但并不一定会发生这些异常;throw 则是指拋出的一个具体的异常类型,执行 throw 则一定抛出了某种异常对象。
5. 通常在一个方法(类)的声明处通过 throws 声明方法(类)可能拋出的异常信息,而在方法(类)内部通过 throw 声明一个具体的异常信息。
6. throws 通常不用显示地捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw 则需要用户自己捕获相关的异常,而后再对其进行相关包装,最后将包装后的异常信息抛出。

常见的异常类有哪些?

(1)NullPointerException 当应用程序试图访问空对象时,则抛出该异常。
(2)SQLException 提供关于数据库访问错误或其他错误信息的异常。
(3)IndexOutOfBoundsException指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
(4)NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
(5)FileNotFoundException当试图打开指定路径名表示的文件失败时,抛出此异常。
(6)IOException当发生某种I/O异常时,抛出此异常。此类是失败或中断的I/O操作生成的异常的通用类。
(7)ClassCastException当试图将对象强制转换为不是实例的子类时,抛出该异常。
(8)ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常。
(9)IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
(10)ArithmeticException当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
(11)NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常。
(12)NoSuchMethodException无法找到某一特定方法时,抛出该异常。
(13)SecurityException由安全管理器抛出的异常,指示存在安全侵犯。
(14)UnsupportedOperationException当不支持请求的操作时,抛出该异常。
(15)RuntimeException 是那些可能在Java虚拟机正常运行期间抛出的异常的超类。

主线程可以捕获到子线程的异常吗?

1. 线程设计的理念:“线程的问题应该线程自己本身来解决,而不要委托到外部。”,正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的,需要通过一些方式来实现
2. 线程边界:Runnable接口的run方法所界定的边界就可以看作是线程代码的边界。线程代码不能抛出任何checked异常。所有的线程中的checked异常都只能被线程本身消化掉
3. Thread的静态方法: Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandle())
4. ExecutorService UncaughtExceptionHandler;

Java集合

1. Java 中常用的容器有哪些?

常见的容器类Java容器类包含List、ArrayList、Vector及map、HashTable、HashMap

2. ArrayList 和 LinkedList 的区别?

1.ArrayList是实现了基于动态数组(可增长数组)的数据结构,LinkedList基于链表(双向链表)的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

3. ArrayList 实现 RandomAccess 接口有何作用?为何 LinkedList 却没实现这个接口?

# 只要List集合实现这个接口,就能支持快速随机访问
发现实现RandomAccess接口的List集合采用一般的for循环遍历,而未实现这接口则采用迭代器
ArrayList的for循环要快于迭代器,但是LinkedList的for循环要慢于迭代器,故前者实现RandomAccess接口,而后者没实现,主要为了增加查询速度。
for loop:for (int i=0, n=list.size(); i < n; i++)list.get(i);
runs faster than this loop:for (Iterator i=list.iterator(); i.hasNext(); )i.next();

4. ArrayList 的扩容机制?

ArrayList:    ArrayList底层是基于数组实现的,是一个动态数组,自动扩容。ArrayList不是线程安全的,只能用在单线程环境下。实现了Serializable接口,因此它支持序列化,能够通过序列化传输;实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问;实现了Cloneable接口,能被克隆;
JDK1.7通过无参构造方法(//初始长度默认10,以默认的大小来初始化内部的数组)、有参构造方法对数组进行初始化//根据传入的最小需要容量minCapacity来和数组的容量长度对比,如果minCapacity大于或等于数组容量,则需要进行扩容;ArrayList在第一次插入元素add()时分配10(默认)个对象空间。假如有20个数据需要添加,那么会在第11个数据的时候(原始数组容量存满时),按照1.5倍增长;之后扩容会按照1.5倍增长(10、15、22、、、)

5. Array 和 ArrayList 有何区别?什么时候更适合用 Array?

Array是数组,声明时就要确定长度,并且长度不可变,ArrayList实现是可变长数组,长度会根据需要自动扩容。
当确定数组长度时,可以使用Array

6. HashMap 的实现原理/底层数据结构?JDK1.7 和 JDK1.8

JDK1.7 :数组 + 链表
JDK1.8 :数组 + 链表 + 红黑树
// 不是线程安全的,核心的点就是put插入数据的过程,get查询数据以及扩容的方式;为什么要有链表: 因为不同的key可能存在相同的hash值,就会形成链式存储;  Capacity:HashMap长度。默认初始化长度是16。LoadFactor:负载因子,默认值0.75f。0.75是为了平衡空间和时间的利用率,为了最大程度避免哈希冲突:负载因子太小(0.5),虽然时间效率提升了hash冲突减少,但是空间利用率降低了,负载因子是1.0的时候,意味着会出现大量的Hash的冲突,底层的红黑树变得异常复杂。对于查询效率极其不利;//在链表元素数量超过8(数组长度>64)时改为红黑树,为6的时候退转为链表。中间有个差值7可以防止链表和树之间频繁的转换扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。    // 为什么 HashMap 中 String、Integer 这样的包装类适合作为 key 键String Integer等包装类,内部已经重写了hashcode和equals方法,保证了Hash值的不可更改性,计算准确性,而且又是final类型,保证了key的不可更改性

7. HashMap 的 put 方法的执行过程?

 在put插入的时候会根据key的hashcode去做hash运算得到一个index值(利用元素key的哈希值对数组长度-1按位与操作得到,为什么不用取模%运算呢?因为java的%比位运算慢10倍左右),根据index值放入数组的相应位置。每一个节点(Node)都会保存自身的hash、key、value、以及下个节点put的头插和尾插: JDK1.7和1.8的主要区别在于头插和尾插方式的修改,多线程下头插容易导致HashMap链表死循环,resize后前后链表逆序 ,在转移过程中修改了原来链表中节点的引用关系。但是如果使用尾插,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了,并且1.8之后加入红黑树对性能有提升。

8. HashMap 的 get 方法的执行过程?

首先向get()方法中传递一个key,对key的hashCode()做hash运算,计算在数组中的index;
在get()方法中调用getNode(hash,key)方法,找到对应的hash桶的位置,判断第一个节点是不是直接命中,如果是直接返回,如果有冲突,则往下遍历通过key.equals(k)去查找对应的Entry。
若为树,则在树中通过key.equals(k)查找,O(logn);
若为链表,则在链表中通过key.equals(k)查找,O(n)。

9. HashMap 的 resize 方法的执行过程?

 如果table == null, 则为HashMap的初始化, 生成空table返回即可;如果table不为空, 需要重新计算table的长度, newLength = oldLength << 1(注, 如果原oldLength已经到了上限, newLength = oldLength);遍历oldTable:首节点为空, 本次循环结束;无后续节点, 重新计算hash位, 本次循环结束;当前是红黑树, 走红黑树的重定位;当前是链表, JAVA7时还需要重新计算hash位, 但是JAVA8做了优化, 通过(e.hash & oldCap) == 0来判断是否需要移位; 如果为真则在原位不动, 否则则需要移动到当前hash槽位 + oldCap的位置;

10. HashMap 的 size 为什么必须是 2 的整数次方?

 HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞。如果是2的次幂,可以运用位与运算代替取模,从而使运算速度加快。

11. HashMap 多线程死循环问题?

Java的HashMap是非线程安全的。多线程下应该用ConcurrentHashMap;
HashMap是采用链表解决Hash冲突,因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生死循环;
put操作的时候,如果size>initialCapacity*loadFactor,那么这时候HashMap就会进行rehash操作,随之HashMap的结构就会发生翻天覆地的变化。很有可能就是在两个线程在这个时候同时触发了rehash操作,产生了闭合的回路;

12. HashMap 的 get 方法能否判断某个元素是否在 map 中?

如果将存在为null也视为不存在,那么get方法可以判断,否则,需要用map.containskey(key)

13. HashMap 与 HashTable 的区别是什么?

HashMap没有Synchronized修饰的,线程不安全,而HashTable是Synchronized修饰的,线程安全的。
HashMap允许Key和Value为null,但是HashTable不允许。
HashMap继承自AbstractMap类。但二者都实现了Map接口。
Hashtable继承自Dictionary类
Hashtable扩容为原容量2倍加1;HashMap扩容为原容量2倍;

14. HashMap 与 ConcurrentHashMap 的区别是什么?

HashMap不支持并发操作,没有同步方法,ConcurrentHashMap支持并发操作,通过继承 ReentrantLock(JDK1.7重入锁)/CAS和synchronized(JDK1.8内置锁)来进行加锁(分段锁),每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。
JDK1.8之前HashMap的结构为数组+链表,JDK1.8之后HashMap的结构为数组+链表+红黑树;JDK1.8之前ConcurrentHashMap的结构为segment数组+数组+链表,JDK1.8之后ConcurrentHashMap的结构为数组+链表+红黑树。

16. ConcurrentHashMap 的实现原理是什么?

JDK1.7版本中,ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成。Segment数组不可扩容,HashEntry可以扩容。
JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap

17. HashSet 的实现原理?

①是基于HashMap实现的,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。封装了一个 HashMap 对象来存储所有的集合元素,所有放入 HashSet 中的集合元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。②当我们试图把某个类的对象当成 HashMap的 key,或试图将这个类的对象放入 HashSet 中保存时,重写该类的equals(Object obj)方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致:当该类的两个的 hashCode() 返回值相同时,它们通过 equals() 方法比较也应该返回 true。通常来说,所有参与计算 hashCode() 返回值的关键属性,都应该用于作为 equals() 比较的标准。③HashSet的其他操作都是基于HashMap的。
public class HashSet<E>  extends AbstractSet<E>  implements Set<E>, Cloneable, java.io.Serializable
{  static final long serialVersionUID = -5024744406713321676L;  // 底层使用HashMap来保存HashSet中所有元素。  private transient HashMap<E,Object> map;  // 定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。  private static final Object PRESENT = new Object();  /** * 默认的无参构造器,构造一个空的HashSet。 *  * 实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。 */  public HashSet() {  map = new HashMap<E,Object>();  }  /** * 构造一个包含指定collection中的元素的新set。 * * 实际底层使用默认的加载因子0.75和足以包含指定 * collection中所有元素的初始容量来创建一个HashMap。 * @param c 其中的元素将存放在此set中的collection。 */  public HashSet(Collection<? extends E> c) {  map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));  addAll(c);  }  /** * 以指定的initialCapacity和loadFactor构造一个空的HashSet。 * * 实际底层以相应的参数构造一个空的HashMap。 * @param initialCapacity 初始容量。 * @param loadFactor 加载因子。 */  public HashSet(int initialCapacity, float loadFactor) {  map = new HashMap<E,Object>(initialCapacity, loadFactor);  }  /** * 以指定的initialCapacity构造一个空的HashSet。 * * 实际底层以相应的参数及加载因子loadFactor为0.75构造一个空的HashMap。 * @param initialCapacity 初始容量。 */  public HashSet(int initialCapacity) {  map = new HashMap<E,Object>(initialCapacity);  }  /** * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。 * 此构造函数为包访问权限,不对外公开,实际只是是对LinkedHashSet的支持。 * * 实际底层会以指定的参数构造一个空LinkedHashMap实例来实现。 * @param initialCapacity 初始容量。 * @param loadFactor 加载因子。 * @param dummy 标记。 */  HashSet(int initialCapacity, float loadFactor, boolean dummy) {  map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);  }  /** * 返回对此set中元素进行迭代的迭代器。返回元素的顺序并不是特定的。 *  * 底层实际调用底层HashMap的keySet来返回所有的key。 * 可见HashSet中的元素,只是存放在了底层HashMap的key上, * value使用一个static final的Object对象标识。 * @return 对此set中元素进行迭代的Iterator。 */  public Iterator<E> iterator() {  return map.keySet().iterator();  }  /** * 返回此set中的元素的数量(set的容量)。 * * 底层实际调用HashMap的size()方法返回Entry的数量,就得到该Set中元素的个数。 * @return 此set中的元素的数量(set的容量)。 */  public int size() {  return map.size();  }  /** * 如果此set不包含任何元素,则返回true。 * * 底层实际调用HashMap的isEmpty()判断该HashSet是否为空。 * @return 如果此set不包含任何元素,则返回true。 */  public boolean isEmpty() {  return map.isEmpty();  }  /** * 如果此set包含指定元素,则返回true。 * 更确切地讲,当且仅当此set包含一个满足(o==null ? e==null : o.equals(e)) * 的e元素时,返回true。 * * 底层实际调用HashMap的containsKey判断是否包含指定key。 * @param o 在此set中的存在已得到测试的元素。 * @return 如果此set包含指定元素,则返回true。 */  public boolean contains(Object o) {  return map.containsKey(o);  }  /** * 如果此set中尚未包含指定元素,则添加指定元素。 * 更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2)) * 的元素e2,则向此set 添加指定的元素e。 * 如果此set已包含该元素,则该调用不更改set并返回false。 * * 底层实际将将该元素作为key放入HashMap。 * 由于HashMap的put()方法添加key-value对时,当新放入HashMap的Entry中key * 与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true), * 新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变, * 因此如果向HashSet中添加一个已经存在的元素时,新添加的集合元素将不会被放入HashMap中, * 原来的元素也不会有任何改变,这也就满足了Set中元素不重复的特性。 * @param e 将添加到此set中的元素。 * @return 如果此set尚未包含指定元素,则返回true。 */  public boolean add(E e) {  return map.put(e, PRESENT)==null;  }  /** * 如果指定元素存在于此set中,则将其移除。 * 更确切地讲,如果此set包含一个满足(o==null ? e==null : o.equals(e))的元素e, * 则将其移除。如果此set已包含该元素,则返回true * (或者:如果此set因调用而发生更改,则返回true)。(一旦调用返回,则此set不再包含该元素)。 * * 底层实际调用HashMap的remove方法删除指定Entry。 * @param o 如果存在于此set中则需要将其移除的对象。 * @return 如果set包含指定元素,则返回true。 */  public boolean remove(Object o) {  return map.remove(o)==PRESENT;  }  /** * 从此set中移除所有元素。此调用返回后,该set将为空。 * * 底层实际调用HashMap的clear方法清空Entry中所有元素。 */  public void clear() {  map.clear();  }  /** * 返回此HashSet实例的浅表副本:并没有复制这些元素本身。 * * 底层实际调用HashMap的clone()方法,获取HashMap的浅表副本,并设置到HashSet中。 */  public Object clone() {  try {  HashSet<E> newSet = (HashSet<E>) super.clone();  newSet.map = (HashMap<E, Object>) map.clone();  return newSet;  } catch (CloneNotSupportedException e) {  throw new InternalError();  }  }
}

18. HashSet 怎么保证元素不重复的?

HashSet类中的add()源码
public boolean add(E e) {return map.put(e, PRESENT)==null;}public V put(K key, V value) {return putVal(hash(key), key, value, false, true); // put 入口 ,当key为null是,当调用hash() //以下给出hash()函数 ,可以看到当为null时,赋值为0.}static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))HashMap的key是不能重复的,而这里HashSet的元素又是作为了map的key,当然也不能重复了。

19. LinkedHashMap 的实现原理?

 对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性;

20. Iterator 怎么使用?有什么特点?

Iterator的使用
(1)Iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
(2)使用next()获得序列中的下一个元素
(3)使用hasNext()检查序列中是否还有元素。
(4)使用remove()将迭代器新近返回的元素删除。
(1) Iterator遍历集合元素的过程中不允许线程对集合元素进行修改,否则会抛出ConcurrentModificationEception的异常。
(2)Iterator遍历集合元素的过程中可以通过remove方法来移除集合中的元素,删除的是上一次Iterator.next()方法返回的对象。
(3)Iterator必须依附于一个集合类对象而存在,Iterator本身不具有装载数据对象的功能。
(4)next()方法,该方法通过游标指向的形式返回Iterator下一个元素。

21. Iterator 和 ListIterator 有什么区别?

ListIterator 继承 Iterator
ListIterator 比 Iterator多方法;
使用范围不同,Iterator可以迭代所有集合;ListIterator 只能用于List及其子类
ListIterator 有 add 方法,可以向 List 中添加对象;Iterator 不能
ListIterator 有 hasPrevious() 和 previous() 方法,可以实现逆向遍历;Iterator不可以
ListIterator 有 nextIndex() 和previousIndex() 方法,可定位当前索引的位置;Iterator不可以
ListIterator 有 set()方法,可以实现对 List 的修改;Iterator 仅能遍历,不能修改

22. Iterator 和 Enumeration 接口的区别?

Enumeration 接口的作用与 Iterator 接口类似,但只提供了遍历 Vector 和 Hashtable 类型集合元素的功能,不支持元素的移除操作。(Vector 和 Hashtable 都不怎么常用)
Enumeration速度是Iterator的2倍,同时占用更少的内存。但是,Iterator远远比Enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象。同时,Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的。

23. fail-fast 与 fail-safe 有什么区别?

1.什么是同步修改?
当一个或多个线程正在遍历一个集合Collection,此时另一个线程修改了这个集合的内容(添加,删除或者修改)。这就是并发修改
2.什么是 fail-fast 机制?
fail-fast机制在遍历一个集合时,当集合结构被修改,会抛出Concurrent Modification Exception。
fail-fast会在以下两种情况下抛出ConcurrentModificationExceptio
(1)单线程环境
集合被创建后,在遍历它的过程中修改了结构。
注意 remove()方法会让expectModcount和modcount 相等,所以是不会抛出这个异常。
(2)多线程环境
当一个线程在遍历这个集合,而另一个线程对这个集合的结构进行了修改;fail-safe任何对集合结构的修改都会在一个//复制的集合上进行修改,因此不会抛出ConcurrentModificationException
fail-safe机制有两个问题(1)需要复制集合,产生大量的无效对象,开销大(2)无法保证读取的数据是目前原始数据结构中的数据。

24. Collection 和 Collections 有什么区别?

1、java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。List,Set,Queue接口都继承Collection。直接实现该接口的类只有AbstractCollection类,该类也只是一个抽象类,提供了对集合类操作的一些基本实现。List和Set的具体实现类基本上都直接或间接的继承了该类。
2、java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态方法(对集合的搜索、排序、线程安全化等),大多数方法都是用来处理线性表的。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

Java并发 42 道

并行和并发有什么区别?

并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行(同一时间段);
并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)(同一时刻)。

线程和进程的区别?

1. 线程是CPU调度的最小单位,进程是资源分配的最小单位。
2. 线程共享本进程的地址空间,进程有单独的地址空间。
3. 进程:运行态、就绪态、阻塞态、创建态、终止态。
4. 一个进程包含多个线程,一个线程只能在一个进程之中。每一个进程最少包含一个线程。
5. 进程之间的切换开销比较大,但是线程之间的切换开销比较小。

守护线程是什么?

守护线程(即daemon thread),是个服务线程,准确地来说就是服务用户线程。 java里线程分2种, 1、守护线程,比如垃圾回收线程,就是最典型的守护线程.2.用户线程,就是应用程序里的自定义线程。
守护线程,专门用于服务其他的线程,如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,连jvm都停止运行了,守护线程当然也就停止执行了。
只要有用户线程还存在,那么就一定有守护线程(至少有垃圾回收线程)

创建线程的几种方式?

一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程;
Thread.currentThread()方法返回当前正在执行的线程对象。GetName()方法返回调用该方法的线程的名字。
二、实现Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
三、实现Callable接口和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

Runnable 和 Callable 有什么区别?

//源码
callable的核心是call方法,允许返回值,可以抛出异常,runnable的核心是run方法,没有返回值,不可以抛出异常;
callable可以使用futureTask.get()获取返回值,但是会阻塞子线程,直到子线程执行结束。
callable和runnable都可以应用于executors。而thread类只支持runnable
//使用场景Runnnable接口的使用场景
1)传递给线程对象执行任务;
2)作为线程池方法execute()的入口参数来执行任务;
Callable接口的使用场景
callable对象实例可以作为线程池的submit()方法入口参数

线程状态及转换?

NEW(新建)   线程新建,但是未启动(调用start()方法)
RUNNABLE(可运行)   有可能是Running或者Ready
BLOCKED(锁池)      线程试图获取对象锁,但是对象锁被其他线程所拥有,线程就会阻塞。当获取对象锁,就会进入运行态。
WAITING(无限等待)   一个线程等待另一个线程的唤醒动作时进入等待状态,直到另一个线程调用notifyAll()或者notify()将其唤醒才会退出阻塞。
TIMED_WAITING(定时等待)   等到超时期满或者被其他线程唤醒结束。例如sleep(),wait()
TERMINATED(终止、结束)    run()方法正常结束或者异常结束

模拟卖票:(线程不安全:Java线程调度是抢占式的 ,解决方法:加同步锁,互斥的线程使用同一把锁)

锁阻塞(线程A和B是互斥锁,一个进程进入同步代码块,另一个进程则进入锁阻塞Blocked状态)

sleep() 和 wait() 的区别?

1. 两个方法来自不同的类,sleep来自Thread类,和wait来自Object类;
2. 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法,wait()要靠其他线程唤醒;
3. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用;
4. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

线程的 run() 和 start() 有什么区别?

//start()方法用start方法来启动线程,真正实现了多线程运行,无需等待run方法体中的代码执行完毕而直接继续执行后续的代码;通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行Runnable)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里的run()方法称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止;
//run()方法run()方法只是类的一个普通方法而已。run方法相当于 **线程的任务处理逻辑的入口方法**,就是线程体,它由java虚拟机在运行相应线程时直接调用,而不是由代码进行调用。

在 Java 程序中怎么保证多线程的运行安全?

1.使用安全类,比如 Java. util. concurrent 下的类。
2.使用自动锁 synchronized。
3.使用手动锁 Lock。
4.保证一个或者多个操作在CPU执行的过程中不被中断。
5.保证一个线程对共享变量的修改,另外一个线程能够立刻看到。
6.保证程序执行的顺序按照代码的先后顺序执行。

Java 线程同步的几种方法?

   //NOTE: 同步是一种高开销的操作,因此应该尽量减少同步的内容
1. 同步方法;synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。
注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类;
2. 同步代码块synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步代码synchronized(object){ }
3. wait与notifywait():使一个线程处于等待状态,并且释放所持有的对象的lock。sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。notifyAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
4. 使用特殊域变量(volatile)实现线程同步可见性。对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性。
5. 使用重入锁实现线程同步(java.util.concurrent包来支持同步)ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和块具有相同的基本行为和语义,并且扩展了其能力。ReentrantLock() : 创建一个ReentrantLock实例 lock() : 获得锁 unlock() : 释放锁
注:关于Lock对象和synchronized关键字的选择: a.最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。 b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁
6. 使用局部变量实现线程同步使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。ThreadLocal() : 创建一个线程本地变量 get() : 返回此线程局部变量的当前线程副本中的值 initialValue() : 返回此线程局部变量的当前线程的"初始值" set(T value) : 将此线程局部变量的当前线程副本中的值设置为value
7. 使用阻塞队列实现线程同步使用LinkedBlockingQueue<E>来实现线程的同步 LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。 队列是先进先出的顺序(FIFO);使用原子变量实现线程同步:AtomicInteger类常用方法:AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicIntegeraddAddGet(int dalta) : 以原子方式将给定值与当前值相加get() : 获取当前值

Thread.interrupt() 方法的工作原理是什么?

 线程的thread.interrupt()方法是中断线程,将会设置该线程的**中断状态位,设置为true,中断的结果线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序本身**。线程会不时地检测这个中断标示位,以判断线程是否应该被中断(中断标示值是否为true)。它并不像stop方法那样会中断一个正在运行的线程。线程处于wait状态时,如果没有其他线程唤醒,那么就会一直处于等待状态,此时可以通过Thread.interrupt中断此线程。

谈谈对 ThreadLocal 的理解?

1. 是什么;ThreadLocal 叫做本地线程变量,ThreadLocal 中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部的副本变量;
2. 用处1、在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。2、线程间数据隔离3、进行事务操作,用于存储线程事务信息。4、数据库连接,Session会话管理。
3. ThreadLocal怎么用?// 注:Entey是一种数据结构,类似Map,有key:value;set()ThreadLocalMap 为 ThreadLocal 的一个静态内部类,里面定义了Entry 来保存数据。而且是继承的弱引用。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。get()获取当前线程,然后通过key threadlocal 获取设置的value
4. 内存泄漏问题key threadlocal 为 null 了,这个 entry 就可以清除了。ThreadLocal是一个弱引用,当为null时,会被当成垃圾回收。突然我们ThreadLocal是null了,也就是要被垃圾回收器回收了,但是此时我们的ThreadLocalMap(thread 的内部属性)生命周期和Thread的一样,它不会回收,这时候就出现了一个现象:ThreadLocalMap的key没了,但是value还在,这就造成了内存泄漏。//解决方法:使用完ThreadLocal后,执行remove操作,避免出现内存溢出情况
5. 为什么key使用弱引用?如果使用强引用,当ThreadLocal 对象的引用(强引用)被回收了,ThreadLocalMap本身依然还持有ThreadLocal的强引用,如果没有手动删除这个key ,则ThreadLocal不会被回收,所以只要当前线程不消亡,ThreadLocalMap引用的那些对象就不会被回收, 可以认为这导致Entry内存泄漏。/**强引用:普通的引用,强引用指向的对象不会被回收;*软引用:仅有软引用指向的对象,只有发生gc且内存不足,才会被回收;    用处:缓存*弱引用:仅有弱引用指向的对象,只要发生gc就会被回收。  *虚引用:虚引用无法获取到被引用的对象,虚引用存在的唯一作用就是当它指向的对象被回收后,虚引用本身会被加入到引用队列中,用作记录它指向的对象已被回收。 作用:管理直接内存-->堆外内存*/

说一说自己对于 synchronized 关键字的了解?

1. synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行
2. 非线程安全的条件1.多线程环境。2.共享资源。3.没有保证原子性、可见性和有序性
3. 实现线程安全的方式主要有三种互斥同步:例如,基于synchronized关键字或者Lock接口实现同步。非阻塞同步:例如,基于CAS操作的原子类,但CAS操作会出现ABA问题,如果需要解决ABA问题,可以引入版本号,也可以改用其他同步方案。无同步方案:例如,通过ThreadLocal实现线程本地存储。
4.  JVM对原子性、可见性、有序性所作的支持关于原子性,保证原子性的方式有很多种,除了操作本身是原子性之外,还可以采用一些原子类保证原子性,可以通过加锁的方式,或者无锁算法保证原子性。本文主要讲述的是利用synchronized关键字保证原子性。关于可见性,Java主要有三个关键字可以保证可见性,volatile关键字,final关键字,synchronized关键字。关于有序性,Java主要有两个关键字可以保证有序性,volatile关键字,synchronized关键字。
5. synchronized  synchronized关键字是Java中实现互斥同步最基本的手段,它是一种悲观锁,是一种可重入锁(通过锁计数器是否为0判定对象持有或者释放锁的状态)synchronized关键字的工作原理:在同步语句块时,synchronized关键字经过编译之后,会在同步块的前后形成monitorenter和monitorexit两个字节码指令,代表对象实例或者Class对象作为线程要持有的锁。在修饰方法时,synchronized关键字经过编译之后,会生成ACC_SYNCHRONIZED标识,代表该方法是一个同步方法。不足:线程的阻塞与唤醒会涉及到操作系统用户态与核心态之间的转换,会消耗大量的时间改进:HotSpot虚拟机开发团队实现了各种锁优化技术,适应性自旋锁,锁消除,锁膨胀,轻量级锁,偏向锁等优化,从而实现线程间更高效的数据共享和解决竞争问题。

如何在项目中使用 synchronized 的?

方法加锁和代码块加锁:同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁,很明显,同步方法锁的范围比较大,而同步代码块范围要小点,一般同步的范围越大,性能就越差,一般需要加锁进行同步的时候,肯定是范围越小越好,这样性能更好

说说 JDK1.6 之后的 synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗?

 JDK1.6 对锁的实现引入了大量的优化,如偏向锁、轻量级锁、自旋锁、适应性自旋锁、锁消除、锁粗化等技术来减少锁操作的开销。锁主要存在四中状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级,这种策略是为了提高获得锁和释放锁的效率。

谈谈 synchronized 和 ReenTrantLock 的区别?

1. 皆为可重入锁    //自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
2. synchronized 依赖于 JVM 而 ReenTrantLock 依赖于 API
3. ReenTrantLock 比 synchronized 增加了一些高级功能:①等待可中断;②可实现公平锁;③可实现选择性通知
4. 性能已不是选择标准,优化后的synchronized 和 ReenTrantLock 性能已经持平。

synchronized 和 volatile 的区别是什么?

作用:
synchronized 表示只有一个线程可以获取作用对象的锁,执行代码,阻塞其他线程。
volatile 表示变量在 CPU 的寄存器中是不确定的,必须从主存中读取。保证多线程环境下变量的可见性;禁止指令重排序。
区别:
synchronized 可以作用于变量、方法、对象; volatile 只能作用于变量。
synchronized 可以保证线程间的有序性(个人猜测是无法保证线程内的有序性,即线程内的代码可能被 CPU 指令重排序)、原子性和可见性; volatile 只保证了可见性和有序性,无法保证原子性。
synchronized 线程阻塞, volatile  线程不阻塞。
volatile 本质是告诉 jvm 当前变量在寄存器中的值是不安全的需要从内存中读取,  synchronized  则是锁定当前变量,只有当前线程可以访问到该变量其他线程被阻塞。
volatile 标记的变量不会被编译器优化; synchronized 标记的变量可以被编译器优化。

谈一下你对 volatile 关键字的理解?

volatile是Java语言提供的一种轻量级的同步机制,用来确保将变量得更新操作通知到其它线程volatile 变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作、有序性实现的是通过插入内存屏障来保证的
// 三种特性:
1. 保证变量的可见性;
2. 对于volatile修饰的变量进行单次读/写操作可以保证原子性,对于i++这样的多次操作不保证原子性,对于多线程也不保证原子性;
3: 防止指令重排(不按我们写的指令顺序执行)(通过在指令序列中插入内存屏障来禁止特定类型的处理器重排序);

说下对 ReentrantReadWriteLock 的理解?

ReentrantReadWriteLock 允许多个读线程同时访问,但是不允许写线程和读线程、写线程和写线程同时访问。读写锁内部维护了两个锁:用于读操作的 ReadLock,用于写操作的 WriteLock;使用场景:读操作远多于写操作的时候;ReentrantReadWriteLock 基于 AQS 实现,它的自定义同步器(继承 AQS)需要在同步状态 state 上维护多个读线程和一个写线程,该状态的设计成为实现读写锁的关键。   ReentrantReadWriteLock 很好的利用了高低位。来实现一个整型控制两种状态的功能,读写锁将变量切分成了两个部分,高 16 位表示读,低 16 位表示写//特点
1. 写锁可以降级为读锁,但是读锁不能升级为写锁;
2. 不管是 ReadLock 还是 WriteLock 都支持 Interrupt,语义与 ReentrantLock 一致;
3. WriteLock 支持 Condition 并且与 ReentrantLock 语义一致,而 ReadLock 则不能使用 Condition,否则抛出 UnsupportedOperationException 异常;
4. 默认构造方法为非公平模式 ,开发者也可以通过指定 fair 为 true 设置为公平模式 //升降级
1、 读锁里面加写锁,会导致死锁;
2.  写锁里面是可以加读锁的,这就是锁的降级

说下对悲观锁和乐观锁的理解?

//悲观锁(多写)共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程,总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁;传统的关系型数据库里边就用到了很多这种锁机制,比如:行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。Java 中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现。
//乐观锁(多读)总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在  **更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和 CAS 算法实现 **   乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于 write_condition 机制,其实都是提供的乐观锁。在 Java 中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式 CAS 实现的。

乐观锁常见的两种实现方式是什么?

实现: 版本号机制和 CAS 算法实现
## 版本号机制1. 数据表中加上一个数据版本号 version 字段,表示数据被修改的次数,当数据被修改时,version 值会 加1。2. 当线程 A 要更新数据值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值为当前数据库中的 version 值相等时才更新,否则重试更新操作。
## CAS 算法(compare and swap(比较与交换)) -- 无锁算法无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)## 操作数1、需要读写的内存值 V2、进行比较的值 A3、拟写入的新值 B当且仅当 V == A 时,CAS 通过原子方式用新值 B 来更新 V 的值,否则不会执行任何操作 (自旋--不断尝试)

乐观锁的缺点有哪些?

## ABA问题 -- A-->B-->A ,CAS会认为没有被修改过JDK 1.5 以后的AtomicStampedReference 类就提供了此种能力,其中的 compareAndSet 方法就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
## 循环时间长开销大自旋 CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给 CPU 带来非常大的执行开销。
## 只能保证一个共享变量的原子操作CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效

CAS 和 synchronized 的使用场景?

CAS 适用于写比较少的情况下(多读场景,冲突一般较少),synchronized 适用于写比较多的情况下(多写场景,冲突一般较多)
1. 对于线程冲突较轻的情况,使用 synchronized 同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗 cpu 资源;而 CAS 基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能.
2. 对于线程冲突严重的情况,CAS自旋的概率会比较大,从而浪费更多的 CPU 资源,效率低于synchronized。

简单说下对 Java 中的原子类的理解?

-- Atomic 是指一个操作是不可中断的
并发包 java.util.concurrent 的原子类都存放在 java.util.concurrent.atomic
1.基本类型  AtomicInteger AtomicLong AtomicBoolean
2.基本类型  AtomicIntegerArray AtomicLongArray AtomicReferenceArray
3.引用类型  AtomicReference:引用类型原子类AtomicStampedReference:原子更新引用类型里的字段原子类AtomicMarkableReference :原子更新带有标记位的引用类型
4.对象的属性修改类型AtomicIntegerFieldUpdater:原子更新整型字段的更新器。AtomicLongFieldUpdater:原子更新长整型字段的更新器。AtomicStampedReference :原子更新带有版本号的引用类型。可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。

atomic 的原理是什么?

 Atomic 包中的类基本的特性就是在多线程环境下,当有多个线程同时对单个(包括基本类型及引用类型)变量进行操作时,具有排他性,即当多个线程同时对该变量的值进行更新时,仅有一个线程能成功,而未成功的线程可以向自旋锁一样,继续尝试,一直等到执行成功;Atomic 系列的类中的核心方法都会调用 unsafe 类中的几个本地方法。包括很多直接内存分配以及原子操作的调用,而它之所以标记为非安全的,是告诉你这个里面大量的方法调用都会存在安全隐患.有可能会导致像C++那样,指针越界到其他线程的情况。

说下对同步器 AQS 的理解?

## 是什么?  构建锁和同步器的框架
全程:AbstractQueuedSynchronizer, java.util.concurrent.locks 包下面,线程安全。
AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器,
-- ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask 等等皆是基于 AQS 的

AQS 的原理是什么?

 如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中。注:CLH队列:CLH(Craig, Landin, and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。AQS 使用一个 int 成员变量 (state) 来表示同步状态,通过内置的 FIFO 队列来完成获取资源线程的排队工作。AQS 使用 CAS 对该同步状态进行原子操作实现对其值的修改。

AQS 对资源的共享模式有哪些?

Exclusive(独占):只有一个线程能执行,如:ReentrantLock,又可分为公平锁和非公平锁:Share(共享):多个线程可同时执行,如:CountDownLatch、Semaphore、CountDownLatch、 CyclicBarrier、ReadWriteLock。

AQS 底层使用了模板方法模式,你能说出几个需要重写的方法吗?

使用者继承 AbstractQueuedSynchronizer 并重写指定的方法;
1. isHeldExclusively() :该线程是否正在独占资源。只有用到 condition 才需要去实现它;
2. tryAcquire(int) :独占方式。尝试获取资源,成功则返回 true,失败则返回 false;
3. tryRelease(int) :独占方式。尝试释放资源,成功则返回 true,失败则返回 false。
4. tryAcquireShared(int) :共享方式。尝试获取资源。负数表示失败;0 表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源.
5. tryReleaseShared(int) :共享方式。尝试释放资源,成功则返回 true,失败则返回 false。

说下对信号量 Semaphore 的理解?

实现同步互斥的一种机制,信号量设为1,那么就可实现互斥。
synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,Semaphore (信号量)可以指定多个线程同时访问某个资源;
Semaphore 经常用于限制获取某种资源的线程数量。获取资源时信号量对应减少1,释放资源时对应信号量加1.

CountDownLatch 和 CyclicBarrier 有什么区别?

CountDownLatch 是计数器,只能使用一次,而 CyclicBarrier 的计数器提供 reset 功能,可以多次使用;CountDownLatch:一个线程(多个线程)等待”,而其他的 N 个线程在完成“某件事情”之后,可以终止,也可以等待   CountDownLatch 是计数器,线程完成一个记录一个,只不过计数不是递增而是递减CyclicBarrier:多个线程,在任意一个线程没有完成,所有的线程都必须等待,CyclicBarrier 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行;## CountDownLatch 应用场景:某一线程在开始运行前等待 n 个线程执行完毕:启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行实现多个线程开始执行任务的最大并行性死锁检测
## CyclicBarrier 应用场景:
CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的应用场景

说下对线程池的理解?为什么要使用线程池?

线程池提供了一种限制和管理资源的方式;
//使用线程池的好处
1. 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗;
2. 提高响应速度:当任务到达时,任务可以不需要的等到线程创建就能立即执行;
3. 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

创建线程池的参数有哪些?

 - corePoolSize:提交一个任务到线程池时,如果当前 poolSize < corePoolSize 时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建.如果调用了线程池的prestartAllCoreThreads() 方法,线程池会提前创建并启动所有基本线程;- maximumPoolSize:线程池允许创建的最大线程数(任务队列要有界)- keepAliveTime : 线程池的工作线程空闲后,保持存活的时间- TimeUnit(线程活动保持时间的单位):天(DAYS)、小时(HOURS)、分钟(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和纳秒(NANOSECONDS,千分之一微秒)。- workQueue(任务队列):用于保存等待执行的任务的阻塞队列;
// 可以选择以下几个阻塞队列:-  ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列(FIFO);-  LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按 FIFO 排序元素,吞吐量通常要高于 ArrayBlockingQueue。静态工厂方法 Executors.newFixedThreadPool() 使用了这个队列;-  SynchronousQueue:不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于 LinkedBlockingQueue,静态工厂方法 Executors.newCachedThreadPool 使用了这个队列;

如何创建线程池?

 - 阿里巴巴的Java技术手册(编码规约)不允许使用Executors去创建线程池,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。- public ThreadPoolExecutor(int corePoolSize, //核心线程数int maximumPoolSize, //最大线程数long keepAliveTime,//非线程存活时间TimeUnit unit,//时间单位BlockingQueue<Runnable> workQueue,//任务队列ThreadFactory threadFactory,//线程工厂RejectedExecutionHandler handler //线程资源被占满后添加新进程的拒绝策略) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.acc = System.getSecurityManager() == null ?null :AccessController.getContext();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}- public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler);}- public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler);}- public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);
}

线程池中的的线程数一般怎么设置?需要考虑哪些问题?

 线程数的设置需要考虑三方面的因素,服务器的配置、服务器资源的预算和任务自身的特性。具体来说就是服务器有多少个CPU,多少内存,IO支持的最大QPS是多少,任务主要执行的是计算、IO还是一些混合操作,任务中是否包含数据库连接等的稀缺资源。线程池的线程数设置主要取决于这些因素。
详细可以参考:https://blog.csdn.net/yuyan_jia/article/details/120298564

执行 execute() 方法和 submit() 方法的区别是什么呢?

1.  execute() 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
2.  submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

JDK 中提供了哪些并发容器?

http://t.zoukankan.com/756623607-zhang-p-6869816.html

谈谈对 CopyOnWriteArrayList 的理解?

CopyOnWriteArrayList这是一个ArrayList的线程安全的变体,其原理大概可以通俗的理解为:初始化的时候只有一个容器,很常一段时间,这个容器数据、数量等没有发生变化的时候,大家(多个线程),都是读取(假设这段时间里只发生读取的操作)同一个容器中的数据,所以这样大家读到的数据都是唯一、一致、安全的,但是后来有人往里面增加了一个数据,这个时候CopyOnWriteArrayList 底层实现添加的原理是先copy出一个容器(可以简称副本),再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。
修改会加锁。

谈谈对 BlockingQueue 的理解?分别有哪些实现类?

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。(生产者、消费者)
主要实现类:

  • ArrayBlockingQueue
    环形数组,存取效率比较高,但是存取用的同一个锁,读写互斥,效率相对就慢了。
  • LinkedBlockingQueue
    存储采用两个锁(ReentrantLock ),存取效率相对较高。
  • PriorityBlockingQueue
    默认按小顶堆存放元素,每次取元素都是取堆顶元素。
  • SynchronousQueue
    同步队列,可以指定公平和非公平方式。队列中每次放一个任务,放第二个的时候就阻塞了,等待消费者消费完,才会唤醒生成线程,继续向队列放任务。
  • DelayQueue
    延时队列会计算延时多久,然后线程将阻塞一段时间,再继续执行任务。

谈谈对 ConcurrentSkipListMap 的理解?

基于跳表实现的并发的、可排序的 Map。它可以在多线程环境中弥补 ConcurrentHashMap 不支持排序的功能不足。

Java JVM

说一下 Jvm 的主要组成部分?及其作用?

JVM主要由类加载器、运行时数据区、执行引擎和本地库接口组成。
1.类加载器:加载.class文件到内存中。
2.运行时数据区:堆、方法区、虚拟机栈、本地方法栈、程序计数器。
3.执行引擎:执行引擎也叫解释器,负责解释命令,提交操作系统执行
4.本地库接口:本地接口的作用是融合不同的编程语言为Java所用。

谈谈对运行时数据区的理解?

主要包括方法区,堆内存,虚拟机栈,本地方法栈以及程序计数器。
方法区:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码等。
堆内存:在虚拟机启动时创建,存放对象实例。
虚拟机栈:为虚拟机执行Java方法服务。
本地方法栈:为虚拟机使用到的 Native方法服务。
程序计数器:是当前线程所执行的字节码的行号指示器。

堆和栈的区别是什么?

  1. 程序内存分区中的堆与栈
    栈由操作系统自动分配释放 ,用于存放函数的参数值、局部变量等,栈描述程序的执行情况
    堆由程序员分配释放, 若程序员不释放,程序结束时由OS回收,堆描述了数据的存储情况。
    2.数据结构中的堆与栈
    栈是操作受限的线性表,先进后出。堆是一种常用的树形结构,排序的堆分为大根堆和小根堆。

堆中存什么?栈中存什么?

堆中存放的是对象和数组。栈中存放的是基本数据类型和堆中对象的引用。

为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?

1.从软件设计的角度来看,栈代表了处理逻辑,而堆代表了数据,这样分离使得处理逻辑更为清晰。体现的是一种隔离、模块化的思想。
2.堆与栈的分离,使得堆中的内容可以被多个栈共享
3.栈因为运行时的需要(如保存系统运行的上下文),需要进行址段的划分。由于栈只能向上增长,因此会限制住栈存储内容的能力。而堆不同,堆的大小可以根据需要动态增长。
堆和栈的完美结合就是面向对象的一个实例。
栈主要用来执行程序,堆主要用来存放对象,为栈提供数据存储服务。也正是因为堆与栈分离的思想才使得JVM的垃圾回收成为可能。

Java 中的参数传递时传值呢?还是传引用?

Java只有值传递。引用对象传的是引用的值,而非引用本身,实质也是值传递。

判断垃圾可以回收的方法有哪些?

引用计数法和可达性分析法。

被标记为垃圾的对象一定会被回收吗?

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的。这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程。

谈谈对内存泄漏的理解?

  1. 内存泄漏定义(memory leak):一个不再被程序使用的对象或变量还在内存中占有存储空间。
    2.内存泄漏的最终结果就是OOM(内存溢出:指程序申请内存时,没有足够的内存供申请者使用).
    3.造成内存泄漏的几种情况?
    3.1.长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。
    3.2.各种连接没有及时释放,比如数据库连接、网络连接、IO连接等。
    3.3.变量的不合理引用。一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。比如在 JS 中使用未定义的变量,会在全局定义一个新变量,就有可能会导致内存泄漏。

尽量避免内存泄漏的方法?

1.减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收。
2.注意程序逻辑,避免“死循环”。
3.避免创建过多的对象。

常用的垃圾收集算法有哪些?

标记清除、复制算法、标记整理(移动存活的)

为什么要采用分代收集算法?

不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率.

分代收集下的年轻代和老年代应该采用什么样的垃圾回收算法?

新生代里的对象躲过15次GC即进入老年代,大对象直接进入老年代。Minor GC之后发现剩余的存活对象太多了,没办法放入另外一块 Survivor 区,就会直接把这些对象直接转移到老年代。
新生代采用复制算法,老年代采用标记整理算法(老年代对象存活量多)。

常用的垃圾收集器有哪些?

参考: http://dlj.bz/U3YW34

谈谈你对类文件结构的理解?有哪些部分组成?谈谈你对类加载机制的了解?

参考:https://blog.csdn.net/LXMXHJ/article/details/124876571

有哪些实际场景是需要打破双亲委派模型的?

Tomcat使用一个web容器部署两个或者多个应用程序。

谈谈你对编译期优化和运行期优化的理解?

参考:https://blog.csdn.net/wr_java/article/details/114399950

说下你对 Java 内存模型的理解?

参考:https://blog.csdn.net/wdj_yyds/article/details/124596323

SSM框架

使用 Spring 框架的好处是什么?

非侵入式设计、方便解耦、简化开发、支持AOP、支持声明式事务处理(只需简单配置就可以使用)、方便程序测试(集成了Junit)、方便集成其他优秀框架、降低Java EE API的使用难度(JDBC等都进行了封装)

解释下什么是 AOP?

aop 是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。

AOP 的代理有哪几种方式?

JDK和CGLIB,默认使用JDK动态代理(基于接口)

谈谈你对 IOC 的理解?

参考:https://www.w3cschool.cn/article/15960248.html

Bean 的生命周期?

实例化Bean:通过反射调用构造方法实例化对象。
依赖注入:装配Bean的属性
实现了Aware接口的Bean,执行接口方法:如顺序执行BeanNameAware、BeanFactoryAware、
ApplicationContextAware的接口方法。
Bean对象初始化前,循环调用实现了BeanPostProcessor接口的预初始化方法
(postProcessBeforeInitialization)
Bean对象初始化:顺序执行@PostConstruct注解方法、InitializingBean接口方法、init-method
方法
Bean对象初始化后,循环调用实现了BeanPostProcessor接口的后初始化方法
(postProcessAfterInitialization)
容器关闭时,执行Bean对象的销毁方法,顺序是:@PreDestroy注解方法、DisposableBean接口
方法、destroy-method

Bean 的作用域?

Singleton,prototype,Request,Session.global-session:

Spring 中的单例 Bean 的线程安全问题了解吗?

参考:http://t.zoukankan.com/east7-p-14702326.html

谈谈你对 Spring 中的事务的理解?

事务的四大特性(ACID):原子性,一致性,隔离性,持久性。
Spring中有两种事务处理方式:声明式事务和编程式事务。

  1. 声明式事务底层建立在IoC和AOP的基础上,在方法的前后进行拦截,在方法执行前创建或者加入一个事务,方法执行后提交或者回滚事务。
  2. 编程式事务:在方法的前后手动的开启和关闭事务,控制的粒度比声明式事务要小,可以达到代码块级别,但代码会很臃肿和复杂,项目中一般不会用。
  3. @Transactional注解来标注声明式事务,前提要开启事务支持(@EnableTranscationManagement)

Spring 中的事务隔离级别?

 //读取未提交数据(会出现脏读, 不可重复读) 基本不使用READ_UNCOMMITTED(1),//读取已提交数据(会出现不可重复读和幻读)READ_COMMITTED(2),//可重复读(会出现幻读)REPEATABLE_READ(4),//串行化(防止脏读,不可重复读外,还避免了幻像读,但花费代价很大)SERIALIZABLE(8);

Spring 中的事物传播行为?

    //支持当前事务(如果当前存在事务,则加入到当前事务,总共一个事务),如果不存在 就新建一个(默认)REQUIRED(0),//支持当前事务,如果不存在,就不使用事务SUPPORTS(1),//支持当前事务,如果不存在,抛出异常MANDATORY(2),//如果有事务存在,挂起当前事务,新建一个新的事务(新建的事务是独立,与当前事务无关)REQUIRES_NEW(3),//以非事务方式运行,如果有事务存在,挂起当前事务NOT_SUPPORTED(4),//以非事务方式运行,如果有事务存在,抛出异常NEVER(5),//如果当前事务存在,则嵌套事务执行,作为当前事务中的一个子事务(依赖外层的事务,外层事务失败,子事务也要回滚)NESTED(6);

Spring 框架中用到了哪些设计模式?

ApplicationContext 通常的实现有哪些?

  1. FileSystemXmlApplicationContext:此容器从一个XML文件中加载bean的定义,XML Bean配置文件的全路径名必须提供给它的构造函数。
  2. ClassPathXmlApplicationContext:此容器也从一个XML文件中加载bean的定义,这里需要正确设置classpath因为这个容器将在classpath里找bean配置。
  3. WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean

谈谈你对 MVC 模式的理解?

模型、视图和控制器分离,增加了代码的灵活性。

View 传送指令到 Controller,Controller 完成业务逻辑后,要求 Model 改变状态,Model 将新的数据发送到 View,用户得到反馈

SpringMVC 的工作原理/执行流程?

SpringMVC 的控制器是不是单例模式,如果是会有什么问题,怎么解决?

默认是单例Bean,多线程下有线程安全问题,但是不建议使用同步处理,会严重影响性能,解决方法就是控制器中不定义成员变量,让其为无状态Bean,就可以保证线程安全。

SpringMVC 里面拦截器是怎么写的?

第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口,或者是这个类继承实现了HandlerInterceptor 接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;
第二种方式是实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。
原文链接:https://blog.csdn.net/a231234aa/article/details/115223326

谈谈你对 MyBatis 的理解?

  1. ORM(对象关系映射)框架,为了解决面向对象与关系数据库存在的互不匹配的现象。
  2. 对JDBC进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  3. 只需要关注sql,输入参数和输出参数。

MyBaits 的优缺点有哪些?

  1. 优点:代码量小,简单,便于集成,支持动态SQL。
  2. 缺点:mybatis的数据库移植性较差,SQL语句编写工作量非常的大,要求熟练度非常的高。

MyBatis 与 Hibernate 有哪些不同?

  1. hibernate是全自动,而mybatis是半自动
  2. hibernate数据库移植性远大于mybatis
  3. hibernate拥有完整的日志系统,mybatis则欠缺一些
  4. mybatis相比hibernate需要关心很多细节
  5. sql直接优化上,mybatis要比hibernate方便很多
  6. 缓存机制上,hibernate要比mybatis更好一些
  7. 原文:https://www.cnblogs.com/lixuwu/p/10941649.html

MyBatis 中 #{} 和 ${}的区别是什么?

#{}是预编译,${}是字符串替换,#{}可以有效防止SQL注入。

MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么?

Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 Mybatis配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。它的原理是,使用 CGLIB 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName(),拦截器 invoke()方法发现 a.getB()是null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 a.getB().getName()方法的调用。这就是延迟加载的基本原理。

说一下 MyBatis 的一级缓存和二级缓存?

  1. Mybatis对缓存提供支持,一级缓存是默认使用的,二级缓存需要手动开启。
  2. 一级缓存的作用域是一个sqlsession内;二级缓存作用域是针对mapper进行缓存
  3. 一级缓存:在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)。
  4. 二级缓存:二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。

MyBatis 动态 SQL 是做什么的?都有哪些动态 SQL?能简述一下动态 SQL的执行原理不?

参考:https://blog.csdn.net/weixin_42495773/article/details/106798472

MySQL

数据库的三范式是什么?

  1. 第一范式(1NF):列不可再分。
  2. 第二范式(2NF)属性完全依赖于主键。
  3. 第三范式(3NF)属性不依赖于其它非主属性 属性直接依赖于主键。

谈谈你对索引的理解?

参考:https://blog.csdn.net/qq_40624026/article/details/125131496

索引的底层使用的是什么数据结构?

InnoDB是B+树,MyIsam是B树。

谈谈你对 B+ 树的理解?

参考:https://xie.infoq.cn/article/9c88e754b6edcba58a3e8776b

为什么 InnoDB 存储引擎选用 B+ 树而不是 B 树呢?

参考:https://cloud.tencent.com/developer/article/1797121

谈谈你对聚簇索引的理解?

关键词:将数据存储和索引放到了一块,找到了索引也就找到了数据。
详细请参考:https://blog.csdn.net/zhizhengguan/article/details/120834883

索引的分类?

主键索引,单列索引,复合索引,唯一索引。

谈谈你对最左前缀原则的理解?

参考:https://blog.csdn.net/qq_43386944/article/details/118599013

怎么知道创建的索引有没有被使用到?

EXPLAIN + SQL语句

什么情况下索引会失效?即查询不走索引?

https://blog.csdn.net/qq_40624026/article/details/125131496

查询性能的优化方法?

方法:空间换时间(索引),随机转顺序

InnoDB 和 MyISAM 的比较?

参考:https://blog.csdn.net/qq_35642036/article/details/82820178

谈谈你对水平切分和垂直切分的理解?

分库分表:https://blog.csdn.net/zhizhengguan/article/details/120875892

主从复制中涉及到哪三个线程?

主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。

I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。

SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。

主从同步的延迟原因及解决办法?

参考:https://blog.csdn.net/hao_yunfeng/article/details/82392261

谈谈你对数据库读写分离的理解?

  1. 主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作.
  2. https://blog.csdn.net/qichangjian/article/details/87944310

谈谈你对事务隔离级别的理解?

MySQL 默认的隔离级别是什么?

可重复读(repeatable read)

说一下 MySQL 的行锁和表锁?

参考:https://blog.csdn.net/xts5701046/article/details/81395958

说明

该博客用于个人学习查阅,部分引用到了其他博客内容,如有错误或者侵权,请联系删除。

Java后端常见问题合集相关推荐

  1. linuex查看繁忙_[个人笔记] 关于linux的常见问题合集

    关于linux的常见问题合集,有技术问题,上 bug200.com 有什么方法可以设置吗chmod 755对于/opt/lampp/htdocs它的所有内容包括子文件夹和文件? 将来,如果我在htdo ...

  2. 【总览】程序员前端、后端资源合集

    [总览]程序员前端.后端资源合集 1.程序员日常聚集交流地 2.前端界面介绍 2.1 辅助工具 2.2 好的架构 2.3 源码 3后端API介绍 3.1 辅助工具 3.2 好的架构 3.3源码 4.前 ...

  3. Java面试核心知识点(283页)Java面试题合集最新版(485页)

    阿里.腾讯两大互联网企业传来裁员消息,很多人都陷入担心,不安情绪蔓延-- 其实大家应该更冷静和理性地看待大厂裁员.每年三四月都是大厂人员调整期,这个季节是各个公司战略调整.战略规划的一个关键期,肯定会 ...

  4. java入门笔记合集(杂乱)(2)

    java入门笔记合集(杂乱)2 StringBuilder 这是一个容器,可以和String搭配起来用 package day1;import java.util.Scanner;public cla ...

  5. macsafari服务器中断撞墙,苹果Mac Safari 常见问题合集(一)

    使用过苹果手机和电脑的朋友们,应该都知道safari浏览器这个软件,这是一款由苹果官方为用户们推出的专业搜索引擎,操作十分的简单便捷,不少的小伙伴们都非常的喜欢,不过在使用的过程中,也会有一些特殊的情 ...

  6. AE常见问题合集,适合初学者

    AE常见问题合集 1. 合成窗口出现红色方框,无法预览画面. 按Caps Lock键即可 2. 中文字体出现乱码. 选择中文字体,尽量不要用希奇古怪的中文字体(毛笔字),一般情况下方正.文鼎是没问题的 ...

  7. 【毕设|Java项目开发合集】(附源码)

    [毕设|Java项目开发合集] 14个Java项目(附源码)助你轻松搞定毕业设计! 1.新冠疫情统计系统 2.家教系统 3.进销存管理系统 4.饮食分享平台 5.宠物领养平台 6.销售评价系统 7.酒 ...

  8. Floorplan后端概念合集

    以下资料是我之前写过的,芯片数字后端中的一些概念介绍,主要是Floorplan部分.整理了一下,做成合集,方便大家查询. 点击标题就可以选择文章查看,会直接挂在公众号的主页菜单栏里的"资料合 ...

  9. 26款JAVA毕设项目合集【java课设】

    最新最全的JAVA项目合集来啦,看完这26套毕设不再发愁 最近UP整理了一些Java项目,从初级练手项目到企业级电商项目,全部配备源码及笔记,如果你能全部吃透,直接成神,各个大厂都为你打开大门! 大家 ...

最新文章

  1. 【HM】第5课:JDBC连接MySQL数据库
  2. sql语句练习50题(Mysql版-详加注释)
  3. CloudFoundry命令行和Kubernetes命令行的Restful API消费方式
  4. NAS服务器局域网内IPad、手机、电视盒子等联网播放
  5. 阿里云Maven镜像配置
  6. OrderOnline——设计概述
  7. 多柱汉诺塔最优算法设计探究
  8. SAP License:无师自通学SAP-开篇
  9. PHP和MySQL Web开发从新手到高手,第1天-搭建PHP开发环境
  10. Ubuntu下自制douban.fm播放器
  11. QQ在线客服代码(绝对强制对话框)
  12. Chrome小恐龙游戏前端修改代码【含原理和代码】
  13. JQuery实现 任务清单案例
  14. vsphere client下载地址
  15. android 自定义图片合集(自定义控件)
  16. 荣品RK3288开发板 怎么接23.5寸,BOA屏?
  17. 软件工程-非功能需求撰写参考案例
  18. 【Mac】使用Karabiner 映射输入法快捷键
  19. 汉诺塔问题(Tower of Hanoi)
  20. 史上最完美的Android沉浸式状态导航栏攻略

热门文章

  1. MapReduce操作实例
  2. AI产品经理面试问题积累
  3. python库-networkx模块
  4. Vue技巧小结(持续更新)
  5. CGAL 点云数据读取与保存
  6. EPLAN教程 | EPLAN表格居然还能这么玩
  7. 划分春夏秋冬四季的气象学标准
  8. 面试逻辑题和答案(二)
  9. I2S音频总线--总结
  10. 写了一个java的连点器程序 但是有时候点击的时候无法暂停 并且暂停之后无法再次运行