本文共 2406 字,大约阅读时间需要 8 分钟。
问题2:
final 用于声明属性,方法和类, 分别表示属性不可变, 方法不可覆盖, 类不可继承. finally 是异常处理语句结构的一部分,表示总是执行 finalize 是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等. JVM不保证此方法总被调用.问题4 :
string 字符串常量 stringbuffer 字符串变量 线程安全。append方法上加了synchronized关键字保证一个时间段内只能有一个线程执行该方法 stringbuilder 字符串变量 线程不安全问题8:
hashmap是线程不安全的 在多线程环境下 可能因为线程竞争 在put()时 因为多线程 某一线程先put的值被覆盖 比如有两个线程A和B,首先A希望插入一个key-value对到HashMap中,首先计算记录所要落到的桶的索引坐标,然后获取到该桶里面的链表头结点,此时线程A的时间片用完了,而此时线程B被调度得以执行,和线程A一样执行,只不过线程B成功将记录插到了桶里面,假设线程A插入的记录计算出来的桶索引和线程B要插入的记录计算出来的桶索引是一样的,那么当线程B成功插入之后,线程A再次被调度运行时,它依然持有过期的链表头但是它对此一无所知,以至于它认为它应该这样做,如此一来就覆盖了线程B插入的记录,这样线程B插入的记录就凭空消失了,造成了数据不一致的行为。 resize()方法 也会有明显的多线程问题 resize()是说创建一个容量是当前桶两倍的桶数组。先将原先的桶的元素逐个移到新桶中,然后将原来的引用置为0 。hashmap的get操作可能因为resize()引起死循环。(cpu100%)void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entrye : table) { while(null != e) { Entry next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }
这个方法的功能是将原来的记录重新计算在新桶的位置,然后迁移过去。
我们假设有两个线程同时需要执行resize操作,我们原来的桶数量为2,记录数为3,需要resize桶到4,原来的记录分别为:[3,A],[7,B],[5,C],在原来的map里面,我们发现这三个entry都落到了第二个桶里面。
假设线程thread1执行到了transfer方法的Entry next = e.next这一句,然后时间片用完了,此时的e = [3,A], next = [7,B]。线程thread2被调度执行并且顺利完成了resize操作,需要注意的是,此时的[7,B]的next为[3,A]。此时线程thread1重新被调度运行,此时的thread1持有的引用是已经被thread2 resize之后的结果。线程thread1首先将[3,A]迁移到新的数组上,然后再处理[7,B],而[7,B]被链接到了[3,A]的后面,处理完[7,B]之后,就需要处理[7,B]的next了啊,而通过thread2的resize之后,[7,B]的next变为了[3,A],此时,[3,A]和[7,B]形成了环形链表,在get的时候,如果get的key的桶索引和[3,A]和[7,B]一样,那么就会陷入死循环。问题九:
websocket是一种应用层协议 基于http的一些原有功能并进行了一些改进。websocket通过http来建立连接,连接建立后通信双方随时都能向彼此发送消息,数据的传输通过帧来进行,不再需要request。是一种全双工通信方式。 一般情况下我们使用 HTTP 有一个很大的缺陷,就是 HTTP 只能由客户端来主动发起,如果有需要服务端主动通知的业务,就需要轮训。轮询的效率低,非常浪费资源。为了解决 Web 端即时通讯的需求就出现了 WebSocket。socket是一种逻辑上的网络传输中端的概念。网络中的socket指的是对传输层(tcp/udp)抽象的接口。是对udp/tcp的而抽象出来的一层api。是位于传输层和应用层之间的一层抽象
转载地址:http://venhb.baihongyu.com/