最近经历的一次面试

    前段时间去了一家互联网公司面试,感觉被虐的挺惨的.主要原因还是自己对jdk不是非常熟悉,面试官没有让自己去写代码实现,也没有考数据结构和算法,只是让说而已.我觉得程序员不是靠说来证明自己,就像那句名言:talk is cheap,show me the code.还有就是和面试官不是很谈得来,就是没有缘分.好了,现在总结一下面试的问题,然后写下关于这些问题的答案.

问题:

    1.画出项目流程图

            我画了,但是面试官说画的比较简单,要求像程序的流程图一样,输入时什么,输出是什么.其实我在公司做的项目是财务部分,  公司 主要追寻敏捷开发,文档太少了,几乎等于没有,我们都是先问下同事关于业务部分,然后直接看代码.而且这个部分的业务非常复杂,没那么简单就能画出,画出来也需要非常多的时间.

    2.volatile关键字作用

            在Jvm内存中有一块是虚拟机栈,每个线程运行的时候都会有自己的栈,线程栈中保存了一份线程变量的备份,是从主存中复制来的,这样在取出来之后的操作中无法保证主存中的数据有没有在线程操作的过程中发生了改变.如果对变量加了volatile修饰,变量每次在使用的时候会从主存中去取,但是这还是会产生并发的问题.所以还是建议使用sychonized比较安全

    3.HashMap在多线程的情况下会不会有问题.

          最容易让人想到的就是脏数据,其次就是循环的问题.

  public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;    //  标记1
        addEntry(hash, key, value, i);
        return null;
    }

    

 void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }

    

 void createEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<>(hash, key, value, e);  //标记2
        size++;
    }


在标记1这个地方假设两个线程都PUT同一个KEY  ,A线程到了这里,然后切到B线程,B线程也到了标记1这里,然后A进入到addEntry方法中这时候,  table数组相应的位置放的就是put进来的Key Value的Entry,同样B线程进入到addEntry就会也生成一个相同key和value的Entry 他的next指向之前A线程创建的Entry,这里就产生了脏数据.

    3.Hashtable 和CocurrentHashMap区别

 public synchronized V put(K key, V value){
 ...
 }
 public synchronized V get(Object key){
 ...
 }

    可见Hashtable几乎对所有的方法上面读加了synchronized关键字,等同于锁住了整个Map表,同一时刻只能有一个线程操作同一个Hashtable对象中被sychonized修饰的方法,效率大大降低.ConcurrentHashMap东西太多了.好多地方看不懂,大概就是分了多个Segment每个Segment里面装的是Entry数组就等于Hashtable,这样操作的粒度就小了好多.在读的时候几乎可以实现全并发,写的时候只是锁对应的Segment,而非整个Segment数组


    4.Thread.sleep(),Object.await(),Object.notify(),Thread.yeild(),Object.join()的区别,

        Thread.sleep(100)是当前线程不让出系统资源的情况下去睡觉,而且不会释放对象锁.Object.wait()是在同步控制块或者方法中使用的,表示被锁的对象进行释放,而,notify是随机唤醒之前在这个对象上进行wait()的线程.而notifyAll是唤醒所有在这个对象wait()的线程,然后由线程去争抢对象锁,因为这些线程都在sychronized中.yeild()是在不释放对象锁的情况下进入就绪队列与相同及以上优先级的线程重新竞争cpu,有可能下次还是调用yeild的线程获取到cpu.Thread.join()开启一个子线程,但是必须要等待子线程执行完成之后再执行Thread.join()之后的代码.

    5.Jvm在什么时候回收,回收算法,jvm内存.

        Jvm内存区域主要分成,堆,虚拟机栈,本地方法栈,方法区,程序计数器.

        程序计数器:是线程私有的,指向的是当前线程执行的字节码指令的地址.如果是本地方法则为空.

        虚拟机栈:线程进入某个方法的时候创建栈帧,用于存放局部变量等信息.  本地方法栈用于本地方法

        方法区:也被成为永代区,这是所有线程共享的区域,存放了类的基本信息,静态变量等,里面还有的变量池,变量池主要存放的是运行前就确定的对象,能在程序运行时进行扩展.

         回收算法主要包括,标记清除,标记整理,复制,分代.  一般情况下使用分代分成新生代和老年代,新生代使用复制算法,老年代是用标记整理算法.

转载于:https://my.oschina.net/u/2250599/blog/394434

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值