面试题整理

Posted Happy王子乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试题整理相关的知识,希望对你有一定的参考价值。

java基础:
0、synchornized和volatile的区别,以及如何使用?
1、synchornized与lock区别?
2、volatile关键字有什么用处?
3、HashMap底层数据结构是什么?扩容机制是如何实现的?HashMap怎么解决碰撞问题的?
4、设计模式有哪些?你实际使用过哪些?
5、ConcurrentHashMap 底层如何实现的?
6、ArrayList ,Vector,LinkedList 区别?
7、注解的原理是什么?
8、java中有哪些集合类?

8、创建线程的方式有哪些?
9、线程池的几个核心参数是什么?
10、线程池中线程数量变多,说下运行的过程?
11、如何配置线程池参数?
12、讲一下jvm内存模型?
13、Java内存区域和内存模型二者区别?
14、什么是双亲委派机制?
15、JVM内存溢出了,如何排查问题?
16、常见的垃圾回收器有哪些?cms和G1区别?
17、怎么做JVM调优?
18、怎么理解分布式和微服务,为什么要拆分服务,会产生什么问题,怎么解决这些问题?
19、怎么理解幂等性,有遇到过实际场景么,怎么解决的,为什么用redis,redis过期了或者数据没了怎么办
20、kafka是怎么保证高可用性的,讲讲它的设计架构,为什么读写都在主分区,这样有什么优缺点
21、Linux如何查看日志,为什么?
22、反爬虫的机制,有哪些方式?
23、负载均衡怎么做的呢,有哪些策略?
24、讲一下常见编码方式?
25、utf-8编码中的中文占几个字节;int型几个字节?
26、静态代理和动态代理的区别,什么场景使用?
27、Java中实现多态的机制是什么?
28、什么是深拷贝和浅拷贝?
29、死锁的四个必要条件?
30、怎么避免死锁?
31、断点续传的实现?
32、什么是 java 序列化?什么情况下需要序列化?
33、throw 和 throws 的区别?

开源框架:
1、spring中IOC和AOP怎么理解?分别用了哪些设计模式?
2、简要描述Spring Bean生命周期?
3、BeanFactory&FacotryBean的区别?
4、Spring Cloud组件有哪些,自己对哪个最了解,讲解一下?
5、Spring是如何解决循环依赖的问题的?比如A autowired B,Bautowired A,内部是如何是如何实现的?
6、自定义注解?

数据库:
1、简要描述SQL语句执行过程?
2、mysql的索引引擎、存储引擎,有哪些,有什么区别?
3、sql优化思路?
4、最左前缀原则是什么?
5、mysql持久化机制是什么?
6、binlog、redolog、undolog,有什么区别?
7、是否用过分库分表,主流分库分表中间件是如何选型的?
8、添加索引的缺点?
9、亿级的数据必须使用like进行查询,如何优化?
10、回表的概念?
11、InnoDb的事务隔离级别?
12、MySql的锁有哪些?

8、redis为什么这么快?
9、Redis的5种基础数据类型及其对应数据结构?
10、redis和memcached、mongodb的区别
11、缓存雪崩、缓存穿透、缓存击穿,概念是什么,如何解决呢?
12、怎么保证缓存和数据库中的数据的一致性?
13、Redis持久化机制有哪些?
14、AOF和RDB区别?AOF和RDB都如何使用?
15、redis的高级用法了解哪些,都用在什么场景?
16、redis的缓存淘汰机制?
17、分布式锁如何实现?
18、如何使用Redis处理热点数据?

数据结构:
1、有哪些常见的树形结构?分别属于二叉树还是多叉树?
2、红黑树有什么特点?
3、B树有什么特点?
4、B+树有什么特点?
5、树、链表、数组,查询时间复杂度分别是多少?

网络协议:
1、网址栏输入网址,按下回车之后发生了什么?
2、三次握手的过程?
3、session 和 cookie 有什么区别?
4、说一下 session 的工作原理?
5、什么是 XSS 攻击,如何避免?
6、什么是 CSRF 攻击,如何避免?
7、为什么不建议使用长链接?使用大量长连接,会有什么问题?
8、七层模型都有哪些?四层模型有哪些?五层模型有哪些?
9、get 和 post 请求有哪些区别?
10、如何实现跨域?

中间件:
1、Apollo有接触吗?
2、ElasticJob有接触吗?
3、MyCat有了解吗?
4、sharding-jdbc有了解吗,它和MyCat有什么区别?

项目设计:
1、设计一个"微信摇一摇"模块,讲一下需要记录什么数据,使用什么技术实现?
2、设计一个"秒杀系统",讲一下如何实现,使用哪些技术,有什么注意点?
3、设计一个"社交模块",要求能够实现A的好友圈,与B的好友圈,进行交集,查询共同好友,讲下大致思路?
4、设计一个"电梯模型系统",全市包括"住宅"、“公寓”、"写字楼"等建筑,安装电梯时,需要进行参数计算,使用开发的系统进行相关数据统计,使全市电梯耗能最低。将一些需要收集哪些数据?

其他:
1、你项目有什么难点?
2、最近有在学习什么?有没有学习规划?
3、对哪块源码感兴趣呢?
4、用几个关键词形容下自己?
5、你是怎么针对面试,进行查漏补缺的?
6、你觉得哪些特质适合这个岗位?
7、有过这类软件的开发经验吗?
8、如果面试通过了,会有顾虑不接受offer吗?
9、对个人薪资,有什么期望?

MySQL思考问题:

1、MySQL 建立了业务字段索引,也建立了主键字段索引,当没命中任何一个索引时,查询的数据是怎么获取的呢?(查询不走索引就是遍历主B+树)
2、“N叉树”的N值在MySQL中是可以被人工调整的么?(5.6以后可以通过page大小来间接控制)
3、没有主键的表,有一个普通索引。怎么回表?(没有主键的表,innodb会给默认创建一个Rowid做主键,rowid就是聚集索引)
4、查看索引数的结构,比如多少个层,多少节点?(如果要精确的,就要解数据文件,这个工具可以看看 https://github.com/jeremycole/innodb_diagrams)
5、页分裂的概念,当主键自增时,为什么不会出现页分裂?(往后追加就好了)
6、在建立联合索引的时候,如何安排索引内的字段顺序(我们的评估标准是,1、索引的复用能力;2、考虑的原则就是空间)
7、索引下推和回表,有什么区别?(“select * from tuser where name like ‘张%’ and age=10 and ismale=1” MySQL 5.6之前,建立联合索引后,通过索引下推,需要根据业务索引找到主键id,再校验age是否等于10;MySQL 5.6 引入的索引下推优化,在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数)
8、事务隔离 -> 事务回滚记录 -> 为什么建议你尽量不要使用长事务(1、事务回滚记录过大,占用空间;2、占用锁资源,也可能拖垮整个库)
9、InnoDB搜索引擎下,更新一条单表SQL,记录日志操作几次磁盘?批量更新一批单表数据,操作几次磁盘?(3次redolog两次 binlog 1次;并发更新的时候会合并写)
10、物理日志redo log和逻辑日志binlog,其中的“物理”、“逻辑”如何理解?(逻辑日志可以给别的数据库,别的引擎使用,已经大家都讲得通这个“逻辑”;物理日志就只有“我”自己能用,别人没有共享我的“物理格式”;)
11、数据库锁分类(全局锁、表级锁、行级锁;全局锁就是对整个数据库实例加锁,全局锁的典型使用场景是,做全库逻辑备份)
12、要删除一个表里面的前10000行数据,有以下三种方法可以做到,你会选择哪一种方法呢?为什么呢?(选第二种,第一种容易引起长事务,第三种容易引起锁冲突)
第一种,直接执行delete from T limit 10000;
第二种,在一个连接中循环执行20次 delete from T limit 500;
第三种,在20个连接中同时执行delete from T limit 500。
13、优化器选择问题,select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;索引两个单字段:a、b。如何解决优化器选择索引问题?(1、采用force index强行选择一个索引;2、把“order by b limit 1” 改成 “order by b,a limit 1”;3、删掉索引b)
14、InnoDB的redo log写满了,会出现什么现象?(更新数据暂停,将redo log中数据,处理一部分,留出部分空间再继续进行,业务感受是有几率性的;)
15、为什么用B+树,不用B树?1、页大小 -> 引发树高;2、B+树不高,稳定性更好;3、链表结构,页加载过程,是加载前一页&后一页,速度比较快;

Java笔试面试题整理第一波

(本系列同步更新于 个人博客小站
本系列整理Java相关的笔试面试知识点。其它几篇文章例如以下:


1、Java变量

Java中主要有例如以下几种类型的变量
  • 局部变量
  • 类变量(静态变量)-- 属于类
  • 成员变量(非静态变量)-- 属于对象

2、关于枚举

  package com.scu.lly;
public class EnumTest {
/**
* 颜色枚举
*/
enum ColorEnum{
RED,
GREEN,
BLUE
}
/**
* 性别枚举
* 可用中文字符。不能单独使用数字
* (枚举值组成:字母、下划线)
*/
enum SexEnum{
男,
女,
MAN,
WOWAM
}
  /**
     * 1、带有构造方法的枚举。构造方法为仅仅能为private(默认可不写private);
     * 2、含带參构造方法的枚举,枚举值必须赋值。
     * 3、枚举中有了其它属性或方法之后。枚举值必须定义在最前面。且须要在最后一个枚举值后面加分号";"
     */
    enum CarEnum{
        BMW("宝马",1000000),
        JEEP("吉普",800000),
        MINI("mini",200000);
        private String name;
        /**
         * 从这里能够看出尽管枚举值不能直接由数字组成,可是我们能够给该枚举类加入一个int类型的值,通过构造方法给其赋值,相当于间接的能够使用数值
         */
        private int price;
        private CarEnum(String name,int price){
            this.name = name;
            this.price = price;
        }
        //加入setter、getter方法
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getPrice() {
            return price;
        }
        public void setPrice(int price) {
            this.price = price;
        }
    }

    /**
     * 由于枚举类都继承了Enum类。故我们定义的enum都不能在继承其它类了,可是能够实现其它接口
     */
    enum CarSetEnum implements Car{
        BMW("宝马"),
        JEEP("吉普"),
        MINI("mini");
        private String name;
        private CarSetEnum(String name){
            this.name = name;
        }
        //加入setter、getter方法
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public void setCarName(String name) {
            this.name = name;
        }
    }

    public static void main(String[] args){
        ColorEnum color = ColorEnum.BLUE;
        switch(color){
        case RED:
            System.out.println("红色");
            break;
        case GREEN:
            System.out.println("绿色");
            break;
        case BLUE:
            System.out.println("蓝色");
            break;
        }
        getSelectedColor(color);
        //測试含构造方法的枚举
        System.out.println("吉普信息:"+CarEnum.JEEP.getName() + ":" +CarEnum.JEEP.price);
        for(CarEnum car : CarEnum.values()){
            System.out.println(car.name);
            System.out.println(car.getPrice());
        }

        //測试实现接口的枚举
        CarSetEnum.BMW.setName("加长宝马");
        System.out.println(CarSetEnum.BMW.getName());
    }

    public static ColorEnum getSelectedColor(ColorEnum color){
        ColorEnum result;
        switch(color){
        case RED:
            System.out.println("红色");
            break;
        case GREEN:
            System.out.println("绿色");
            break;
        case BLUE:
            System.out.println("蓝色");
            break;
        }
        result = color;
        return result;
    }

    interface Car{
        public void setCarName(String name);
    }

}

3、訪问控制修饰符

修饰符说明
private
私有的,在同一类内可见。
默认没写同一包(包含子类和非子类)内可见。

默认不使用不论什么修饰符。

protected受保护的。对同一包内的类全部子类可见。
public共同拥有的。对全部类可见。


主要是默认和protected这两个修饰符,总结起来就是:
    默认的:同一包下可訪问;
    protected:同一包和全部子类可訪问;

(1)这里的可见、可訪问指的是能不能通过 ”类的对象.变量名“的方式訪问,这是由于除static声明的变量属于类变量外,其它的都属于实例变量,是属于某个对象的。
如。Person p = new Person(); p.age直接訪问age变量,对于那些私有的变量,非常多情况下会对外提供public的setter和getter方法来供外部訪问。

(2)要注意的是,对于有继承关系的子类来说,比方 class A extends B,A直接继承拥有默认的(在同一包下)protectedpublic的这个字段,能够直接使用该字段,而不用通过再次的实例化父类或"父类对象.字段"的形式訪问。由于在实例化A类的时候父类B已经实例化好了。特别的,对于protected来说,例如以下形式是编译不能通过的。
package com.a
public class A extends B{
    public void test(){
        B b = new B();
        String str = b.age;//错误!不同包下的子类不能通过实例出来的父类获取protected的变量
        String str2 = age;//正确。A类继承了B。直接拥有了该字段
        String str3 = b.birthday;//正确。birthday为public
    }
}

package com.b
public class B{
    protected String age = "20";
    public String birthday = "1995";
}

结论就是:
    在上面那个表格修饰符的约束前提下,对于非继承类关系,须要使用 “实例变量.变量名的形式訪问”(static类变量除外);
    对于有继承关系的子类来说。    子类直接继承了拥有默认的(在同一包下)protectedpublic的这个字段,能够直接使用该字段。

4、UTF-8和GBK编码转换

    
    以下哪段程序能够正确的实现了GBK编码字节流到UTF-8编码字节流的转换:byte[] src,dst;
    
    A、dst=String.fromBytes(src,"GBK").getBytes("UTF-8")
    B、dst=new String(src,"GBK").getBytes("UTF-8")
    C、dst=new String("GBK",src).getBytes()
    D、dst=String.encode(String.decode(src,"GBK")),"UTF-8" )
    
正确答案:B
    操作步骤就是先解码再编码,先通过GBK编码还原字符串。在该字符串正确的基础上得到“UTF-8”所相应的字节串。


5、try、catch、finally运行顺序问题


    以下函数将返回?
1
2
3
4
5
6
7
8
9
publicstaticintfunc (){
    try{
        return1;
    }catch(Exception e){
        return2;
    }finally{
        return3;
    }
}
A、1    B、2    C、3     D、编译错误

正确答案:C
(1)try catch中仅仅要有finally语句都要运行(有特例:假设try 或 catch 里面有 exit(0)就不会运行finally了);
(2)finally语句在try或catch中的return语句运行之后返回之前运行。且finally里的改动语句不能影响try或catch中 return已经确定的返回值。
        若finally里也有return语句则覆盖try或catch中的return语句直接返回。
 (3)在遵守第(2)条return的情况下,运行顺序是:try-->catch(假设有异常的话)-->finally


6、静态代码块、子类、父类初始化顺序

例如以下代码的输出结果:
package com.scu.lly;

public class HelloB extends HelloA {
     public HelloB() {
         System.out.println("-----------HelloB 构造方法------------");
     }

     {
         System.out.println("I’m B class");
     }

     static{
         System.out.println("static B");
     }
     public static void main(String[] args){
         new HelloB();
     }
}

class HelloA{
     public HelloA(){
         System.out.println("-----------HelloA 构造方法------------");
     }

     {
         System.out.println("I’m A class");
     }

     static{
         System.out.println("static A");
     }
}

输出结果:
static A
static B
I’m A class
-----------HelloA 构造方法------------
I’m B class
-----------HelloB 构造方法------------

运行顺序:1.静态代码块 --> 2.普通代码块 --> 3.构造方法
须要明确的是,1是类级别的,2和3是实例级别的,所以在父子类关系中,上述的运行顺序为:

父类静态代码块-->子类静态代码块-->父类普通代码块-->父类构造方法-->子类代码块-->子类构造方法。

也就是上到下(父类到子类)先走完 类级别的(静态的)--> 再依次走完父类的全部实例级别代码 --> 再走子类全部实例级别代码

7、关于null对象、static变量和方法

有关下述Java代码描写叙述正确的选项是____。
1
2
3
4
5
6
7
8
publicclassTestClass {
   privatestaticvoidtestMethod(){
        System.out.println("testMethod");
   }
   publicstaticvoidmain(String[] args) {
        ((TestClass)null).testMethod();
   }
}
        A、编译不通过
        B、编译通过,运行异常。报NullPointerException
        C、编译通过,运行异常,报IllegalArgumentException
        D、编译通过。运行异常,报NoSuchMethodException
        E、编译通过,运行异常,报Exception
        F、运行正常,输出testMethod

正确答案:F

    静态方法是属于类的,静态方法在对象实例创建前就已经存在了,它的使用不依赖于对象是否被创建。

当我们通过类的实例来调用时,最后实际上还是将对象实例转换成了类去掉用该静态方法,所以这里的null仅仅是迷惑大家的跟它没有什么关系。

    这里 ((TestClass)null).testMethod();也能够写成TestClass t = null; t.testMethod();相同能够正确输出。null能够被强制转换成随意类型对象,尽管这个时候t被赋为了空,但这个“空对象”也是属于TestClass的,那么这个“空对象”也就能够去堆上的静态方法区调用testMethod()方法了。
    假设这里testMethod把static去掉,该testMethod方法就变成了实例对象的方法了。这时。能够编译通过,可是会报空指针。

同理,对于static变量也是一样的。

比方TestClass 中有例如以下变量:private static String str = "abc"; 我们通过TestClass t = null; System.out.println(t.str);相同能够正确输出。


8、关于线程启动

下列方法中哪个是运行线程的方法? ()
A、run()    B、start()    C、sleep()    D、suspend()

正确答案:A
start()方法启动一个线程。使其处于就绪状态,得到了CPU就会运行,而调用run()方法,就相当于是普通的方法调用,会在主线程中直接运行,此时没有开启一个线程。

例如以下:

           Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("----------线程中run---------");
                }
            });
            System.out.println("-------主线程11111------");
            t.run();
            System.out.println("-------主线程222------");

这里调用Thread的run()方法,此时相当于是普通的方法调用,并没有开启线程,直接在主线程中运行Thread中的Runnable方法,睡眠2秒后打印"----------线程中run---------",在运行t.run后面的打印。所以此时的输出为:
-------主线程11111------
----------线程中run---------
-------主线程222------
若将t.run()改为t.start(),此时会开启一个线程,并使该线程处于就绪状态,得到CPU后開始运行,调用t.start()后主线程继续运行以下的打印。所以此时的输出为:
-------主线程11111------
-------主线程222------
----------线程中run---------

9、关于内部类

往OuterClass类的代码段中插入内部类声明, 哪一个是错误的:
1
2
3
4
public class OuterClass{
    private float f=1.0f;
    //插入代码到这里
}
A、class InnerClass{
public static float func(){return f;}
}
B、abstract class InnerClass{
public abstract float func(){}
}
C、static class InnerClass{
protected static float func(){return f;}
}
D、public class InnerClass{
 static float func(){return f;}
}
正确答案:ABCD
静态的内部类才干够定义static方法,排除AD;
B抽象方法中不能有方法体;
C,静态方法不能够引用非静态变量。

10、Final修饰符、volatile修饰符


Final修饰符,用来修饰类、方法和变量。final修饰的类不能够被继承,修饰的方法能够被继承,重载,可是不能被子类重写(即又一次定义)

(1)final变量:
被声明为final的对象引用不能指向不同的对象。可是final对象里的数据能够被改变。

也就是说final对象的引用不能改变。可是里面的值能够改变。比方:

        final Person p = new Person();
        p.name = "aaa";
        p.name = "bbb";
可是,假设是final String str = "aaa";     str = "bbb";//错误编译不能通过,由于此时str的引用已经改变了。

(2)final修饰方法

Final修饰的方法能够被子类继承,可是不能被子类改动(重写)。

声明final方法的主要目的是防止该方法的内容被改动。


volatile修饰符,Volatile修饰的成员变量在每次被线程訪问时。都强迫从共享内存中重读该成员变量的值。

而且,当成员变量发生变化时。强迫线程将变化值回写到共享内存。

这样在不论什么时刻。两个不同的线程总是看到某个成员变量的同一个值。

一个volatile对象引用可能是null。


11、StringBuffer 和 StringBuilder

和String类不同。StringBuffer和StringBuilder类的对象能够被多次的改动。而且不产生新的未使用对象。

StringBuilder类和StringBuffer之间的最大不同在于StringBuilder的方法不是线程安全的(不能同步訪问)。

由于StringBuilder相较于StringBuffer有速度优势。所以多数情况下建议使用StringBuilder类。

然而在应用程序要求线程安全的情况下,则必须使用StringBuffer类。


12、可变參数

JDK 1.5 開始,Java支持传递同类型的可变參数给一个方法,一个方法中仅仅能指定一个可变參数,它必须是方法的最后一个參数。不论什么普通的參数必须在它之前声明。
如,public void getStr(String ...str){}//正确

public void getStr2(String ...str,int a){}//错误,一个方法中可变參数仅仅能有一个,它必须是方法的最后一个參数。

13、关于异常分类

全部的异常类是从java.lang.Exception类继承的子类。

Exception类是Throwable类的子类。

除了Exception类外,Throwable另一个子类Error 。

Error用来指示运行时环境发生的错误。层次关系如图:

技术分享技术分享


检查性异常: 不处理编译不能通过
非检查性异常:不处理编译能够通过。假设有抛出直接抛到控制台。


运行时异常(RuntimeException): 继承自RuntimeException类的就是非检查性异常
非运行时异常: 就是检查性异常

以下的表中列出了Java的非检查性异常(RuntimeException

异常描写叙述
ArithmeticException当出现异常的运算条件时。抛出此异常。

比如,一个整数"除以零"时。抛出此类的一个实例。

ArrayIndexOutOfBoundsException用非法索引訪问数组时抛出的异常。假设索引为负或大于等于数组大小,则该索引为非法索引。

ArrayStoreException试图将错误类型的对象存储到一个对象数组时抛出的异常。

ClassCastException当试图将对象强制转换为不是实例的子类时。抛出该异常。
IllegalArgumentException抛出的异常表明向方法传递了一个不合法或不对的參数。

IllegalMonitorStateException抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其它正在等待对象的监视器而本身没有指定监视器的线程。

IllegalStateException在非法或不适当的时间调用方法时产生的信号。换句话说。即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。

IllegalThreadStateException线程没有处于请求操作所要求的适当状态时抛出的异常。
IndexOutOfBoundsException指示某排序索引(比如对数组、字符串或向量的排序)超出范围时抛出。
NegativeArraySizeException假设应用程序试图创建大小为负的数组,则抛出该异常。

NullPointerException当应用程序试图在须要对象的地方使用 null 时,抛出该异常
NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。

SecurityException由安全管理器抛出的异常,指示存在安全侵犯。

StringIndexOutOfBoundsException此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。

UnsupportedOperationException当不支持请求的操作时,抛出该异常。

以下的表中列出了Java定义在java.lang包中的检查性异常类

异常描写叙述
ClassNotFoundException应用程序试图载入类时。找不到相应的类,抛出该异常。
CloneNotSupportedException当调用 Object 类中的 clone 方法克隆对象。但该对象的类无法实现 Cloneable 接口时,抛出该异常。
IllegalAccessException拒绝訪问一个类的时候。抛出该异常。

InstantiationException当试图使用 Class 类中的 newInstance 方法创建一个类的实例。而指定的类对象由于是一个接口或是一个抽象类而无法实例化时。抛出该异常。
InterruptedException一个线程被另一个线程中断,抛出该异常。
NoSuchFieldException请求的变量不存在
NoSuchMethodException请求的方法不存在


其它

1、以下描写叙述属于java虚拟机功能的是?
A、通过 ClassLoader 寻找和装载 class 文件
B、解释字节码成为指令并运行。提供 class 文件的运行环境
C、进行运行期间垃圾回收
D、提供与硬件交互的平台
正确答案:ABCD

2、以下有关java threadlocal说法正确的有?
A、ThreadLocal存放的值是线程封闭。线程间相互排斥的。主要用于线程内共享一些数据,避免通过參数来传递
B、线程的角度看,每个线程都保持一个对其线程局部变量副本的隐式引用,仅仅要线程是活动的而且 ThreadLocal 实例是可訪问的;在线程消失之后。其线程局部实例的全部副本都会被垃圾回收
C、在Thread类中有一个Map,用于存储每个线程的变量的副本。


D、对于多线程资源共享的问题,同步机制採用了“以时间换空间”的方式,而ThreadLocal採用了“以空间换时间”的方式


正确答案:ABCD
    ThreadLocal类用于创建一个线程本地变量
    在Thread中有一个成员变量ThreadLocals,该变量的类型是ThreadLocalMap,也就是一个Map。它的键是threadLocal。值就是变量的副本。ThreadLocal为每个使用该变量的线程都提供了一个变量值的副本,每个线程都能够独立地改变自己的副本,是线程隔离的。通过ThreadLocal的get()方法能够获取该线程变量的本地副本。在get方法之前要先set,否则就要重写initialValue()方法。

    ThreadLocal不是用来解决对象共享訪问问题的。而主要是提供了保持对象的方法和避免參数传递的方便的对象訪问方式。普通情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其它线程是不须要訪问的。也訪问不到的。各个线程中訪问的是不同的对象。



3、以下集合对象中哪几个是线程安全的?( )
A、ArrayList
B、Vector
C、Hashtable
D、Stack
正确答案:BCD

在集合框架中。有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许很多多非线程安全的类。 以下是这些线程安全的同步的类:

vector:比arraylist多了个同步化机制(线程安全)。由于效率较低,如今已经不太建议使用。在web应用中。特别是前台页面,往往效率(页面响应速度)是优先考虑的。

statck:堆栈类,继承了Vector

hashtable:比hashmap多了个线程安全

enumeration:枚举,相当于迭代器

除了这些之外,其它的都是非线程安全的类和接口。比方经常使用的ArrayList、HashMap都是线程不安全的。





以上是关于面试题整理的主要内容,如果未能解决你的问题,请参考以下文章

100道Java面试题收集整理及参考答案

精心整理全网最全Tomcat面试专题及答案tomcat面试看这篇就够了!(共19题,含答案解析)

2022Android面试题合集最新整理版,移动开发架构师筑基必备

2022Android面试题合集最新整理版,移动开发架构师筑基必备

架构师带你面试④Java虚拟机(JVM)面试题2020

100道Java基础面试题收集整理(附答案)