`
bawking
  • 浏览: 34288 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

初看Java容器的艺术(待续)

阅读更多
接口关系
    0上层接口为:Collection & Map
    Collection:Set、List、Queue;
              Set:HashSet、TreeSet
              List:ArrayList、Vector、LinkedList、
         Queue:LinkedList、PriorityQueue、LinkedBlockingQueue(JDK1.5)等
             Map:HashMap、Hashtable、TreeMap、WeekHaspMap、ConcurrentHashMap、LinkedHashMap等
   这些都是些线型结构(栈、队列、链表等)、网型结构(图、树等)、混型结构(线网混合)。    而比较所有这些结构中,主要从几个方面:
     1、基本数据存储(部分结构还有强引用、软引用、弱引用之分)
     2、是否排序
     3、Thread Safe?
  **Set(HashSet,TreeSet)
  1、两种主要Set都是用的HashMap等存储,所以HashMap所拥有的特性Set都拥有,如果熟悉map的话,Set很容易理解;
  2、HashSet是不排序Map,TreeSet是排序Map;
  3、是不是thread safe看add()方法,既然Set直接用的是map.put(),HashMap的put()方法线程不安全。如下:

Java代码
public boolean add(E o) { 
return m.put(o, PRESENT)==null; 
   } 
public boolean add(E o) {
return m.put(o, PRESENT)==null;
}
   
**List(CopyOnWriteArrayList,ArrayList,Vector,LinkedList)
    1、ArrayList、Vector都是用的数组,如下:

Java代码
E[] elementData; 
E[] elementData;
    LinkedList是一个链表,用的“内部静态节点”(静态内部类用于内部使用,可访问创建类的静态变量或方法),如下:

Java代码
private transient Entry<E> header = new Entry<E>(null, null, null); 
   
private transient Entry<E> header = new Entry<E>(null, null, null);
   CopyOnWriteArrayList用的数组,如下:

Java代码
private volatile transient E[] array; 
private volatile transient E[] array;
    链表和数组的区别,这里不说了。     2、这几种List都是不排序的,排序需要应用自己控制。
    3、ArrayList、LinkedList都是线程不安全的,Vector、CopyOnWriteArrayList是线程安全的。Vector、 CopyOnWriteArrayList通过synchronized关键字保证的,这种方式效率不高,1.5有更好的“锁”方式;

Java代码
public synchronized boolean add(E o) 
public synchronized boolean add(E o)
CopyOnWriteArrayList的add有点特殊,如下:

Java代码
public synchronized boolean add(E element) { 
       int len = array.length; 
       E[] newArray = (E[]) new Object[len+1]; 
       System.arraycopy(array, 0, newArray, 0, len); 
       newArray[len] = element; 
       array = newArray; 
       return true; 
   } 
public synchronized boolean add(E element) {
int len = array.length;
E[] newArray = (E[]) new Object[len+1];
System.arraycopy(array, 0, newArray, 0, len);
newArray[len] = element;
array = newArray;
return true;
}
**Queue(ProorityQueue,SynchronousQueue,LinkedBlockQueue,ConcurrentLinkedQueue)
    1、PriorityQueue的存储结构为:

Java代码
private transient Object[] queue; 
  private transient Object[] queue;
     SynchronousQueue存储结构为,但是他的大小总为0:

Java代码
private transient Node head; 
private transient Node head;

    LinkedBlockingQueue的存储结构也同LinkedList类似,也是“内部静态节点”。

Java代码
private transient Node<E> head; 
  private transient Node<E> head;
   当一个消费者试图读取一个空的LinkedBlockingQueue时,它可以不返回,制定等待时间一直等待生产者的出现,想要将一个项插入到满队列的尝试也会导致阻塞调用线程,直到队列的存储空间可用。
  

    2、PriorityQueue、LinkedBlockingQueue、ConcurrentLinkedQueue都不做排序,SynchronousQueue排序没有意义。
  

    3、PriorityQueue是线程不安全,而LinkedBlockingQueue是1.5的新特性,如果高效保证线程安全是主要工作,主要是处于对于synchronzied关键字效率低的优化,主要运用了锁队列等机制。
    SynchronousQueues每个插入操作必须等待另一个线程的对应移除操作,反之亦然,这个容器容量甚至不为1,即size总为0,测试程序如下:

Java代码
static class cosumer extends Thread{ 
         BlockingQueue que; 
        .... 
        public void run(){ 
            System.out.println(que.take());//  如果队列size==0的时候,线程阻塞,直到其他线程put数据 
        } 
    } 
    static class producer extends Thread{ 
        BlockingQueue que; 
        public void run(){ 
            que.put(System.currentTimeMillis());// 队列发生阻塞,当前线程阻塞,知道其他线程take走数据 
            System.out.println(que.size()); // print 0 
            que.put(System.currentTimeMillis()); 
            System.out.println(que.size());// print 0 
        } 
    } 
    public static void testsynQueue(){ 
        BlockingQueue que=new SynchronousQueue(); 
        new cosumer(que).start(); 
        new producer(que).start(); 
    } 
static class cosumer extends Thread{
BlockingQueue que;
....
public void run(){
System.out.println(que.take());//  如果队列size==0的时候,线程阻塞,直到其他线程put数据
}
}
static class producer extends Thread{
BlockingQueue que;
public void run(){
que.put(System.currentTimeMillis());// 队列发生阻塞,当前线程阻塞,知道其他线程take走数据
System.out.println(que.size()); // print 0
que.put(System.currentTimeMillis());
System.out.println(que.size());// print 0
}
}
public static void testsynQueue(){
BlockingQueue que=new SynchronousQueue();
new cosumer(que).start();
new producer(que).start();
}
   会发现线程阻塞。

  **Map(HashMap,LinkedHashMap,TreeMap,Hashtable,WeakHashMap,IdentityHashMap,ConcurrentHashMap)

    1、HashMap、Hashtable存储结构为

Java代码
transient Entry[] table 
transient Entry[] table
     TreeMap为:private transient Entry<K,V> root = null;(存储结构决定了数据操作,节点型数据有利于排序),可以猜出LinkedHashMap为节点型存储结构:

Java代码
private transient Entry<K,V> header; 
private transient Entry<K,V> header;
WeakHashMap为:private Entry[] table;

      ConcurrentHashMap高并发Map是把数据分割成了很多final Segment[] segments;

可以看到为实体数组。

     HashMap插入的顺序与输出的顺序是不同的,那么是以什么顺序做插入的呢?我们看看put方法:

Java代码
public V put(K key, V value) { 
      K k = maskNull(key); 
      int hash = hash(k); // HashMap自行计算hashcode 
      int i = indexFor(hash, table.length);// 根据hash值来判定数组位置 
 
      for (Entry<K,V> e = table[i]; e != null; e = e.next) {// 查找table[i]链表是否有符合的值 
          if (e.hash == hash && eq(k, e.key)) { // 注意这里的eq(),他会比较K的equals()的返回值,这也就为什么重写hashcode后,同时需要重写equals方法,不然就为Object的equals方法了。 
              V oldValue = e.value; 
              e.value = value; 
              e.recordAccess(this); 
              return oldValue;// 如果是已装入容器的对象,则直接返回 
          } 
      } 
 
      modCount++; 
      addEntry(hash, k, value, i);// 如果没有,入table[i]链表中 
      return null; 
  } 
  public V put(K key, V value) {
K k = maskNull(key);
int hash = hash(k); // HashMap自行计算hashcode
int i = indexFor(hash, table.length);// 根据hash值来判定数组位置
for (Entry<K,V> e = table[i]; e != null; e = e.next) {// 查找table[i]链表是否有符合的值
if (e.hash == hash && eq(k, e.key)) { // 注意这里的eq(),他会比较K的equals()的返回值,这也就为什么重写hashcode后,同时需要重写equals方法,不然就为Object的equals方法了。
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;// 如果是已装入容器的对象,则直接返回
}
}
modCount++;
addEntry(hash, k, value, i);// 如果没有,入table[i]链表中
return null;
}
Java代码
// addEntry操作主要如下,这里的bucketIndex是插入的位置 
void addEntry(int hash, K key, V value, int bucketIndex) { 
    Entry<K,V> e = table[bucketIndex]; 
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 
        if (size++ >= threshold) 
            resize(2 * table.length);//HashMap自行扩展table[]空间,复制的时候会消耗性能 
    } 
// addEntry操作主要如下,这里的bucketIndex是插入的位置
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);//HashMap自行扩展table[]空间,复制的时候会消耗性能
}
    bucketIndex是通过indexFor(hash, table.length)来的,然后看看indexFor

Java代码
/**
     * Returns index for hash code h. 
     */ 
    static int indexFor(int h, int length) { 
        return h & (length-1); 
    } 
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}
所以显然顺序就不同的了,如果要保持顺序,可以用TreeMap,LinkedHashMap

     WeekHashMap为private static class Entry<K,V> extends WeakReference<K> implements         Map.Entry<K,V>,他是继承了WeakReference,弱引用是不入JVM的引用队列的,所以随时可能被GC回收。

     LinkedHaspMap是一个双向链表存储结构存储Entry
     存储结构为:private transient Entry<K,V> header,非数组结构,为链表结构;

     线程非安全

     排序的,插入顺序与输出顺序一致,遍历的时候

      ConcurrentHashMap

    StringBuffer和StringBuilder

    在StringBuilder的comments中有段如下的注释:

Java代码
/* This class is designed for use as a drop-in replacement for
* <code>StringBuffer</code> in places where the string buffer was being
* used by a single thread (as is generally the case).  
*/ 

转自:http://www.huomo.cn/developer/article-e710.html
分享到:
评论

相关推荐

    Java收集的代码段1(待续)常用代码段

    在Java编程中,窗口风格、窗口居中、组件拖动、文件路径处理和设置...对于"Java收集的代码段1(待续)常用代码段"这个主题,后续可能还会涉及到更多高级特性和实践技巧,持续学习和实践是提升Java GUI编程能力的关键。

    毕业就业-刷题库Java面试题大全(2021年-2022年).rar

    a面试大全2021是一套最新Java面试必问合集,这本面试手册包含了Java基础、Java集合、JVM、Spring、Spring Boot、Spring Cloud、Mysql、Redis、RabbitMQ、Dubbo、Netty、分布式及架构设计等方面的技术点。内容难度...

    java100道选择题含答案

    Java 选择题含答案 本资源总结了 Java 选择题含答案,涵盖了 Java 语言基础知识、数据类型、运算符、控制结构、方法、数组、字符串、面向对象编程、多线程、IO 操作等方面。 Java 语言基础知识 ...(待续)

    java程序员面试之150++(待续)

    在Java程序员面试中,面试官通常会关注求职者对Java基础知识的掌握程度,包括但不限于类的作用域、匿名内部类、内部类的类型、位运算符与逻辑运算符的区别、集合框架的理解、断言的使用、字符串对象的创建、数学方法...

    JAVA期末考试试题及答案.doc

    JAVA期末考试试题及答案 根据提供的文件信息,我们可以生成以下知识点: 1. JAVA 语言程序设计考试试题:单选题 * 题目 1:下列语句序列执行后,k 的值是多少?(B) int m=3, n=6, k=0;...(待续)

    自考Java语言程序设计一填空题汇总.pdf

    本资源摘要信息涵盖了Java语言程序设计的基础知识点,包括Java语言的特点、Java开发环境、Java语法基础、变量和数据类型、运算符和控制结构等方面。 一、Java语言特点 Java语言是目前最广泛的编程语言之一,具有...

    java基础知识测试题

    根据提供的文件信息,这里将对每一道题目进行详细的解析,并解释相关的 Java 基础知识点。 ### 1. Java 的关键字选择题 **题目:** 下列哪个是 Java 中的关键字? - A. sizeof - B. abstract - C. NULL - D. ...

    java面试题集锦 java基础、集合、多线程等

    Java 面试题集锦 Java 基础知识点: 1. JDK 和 JRE 的区别: JDK(Java Development Kit)是 Java 开发工具包,提供了 Java 的开发环境和运行环境。JRE(Java Runtime Environment)是 Java 运行环境,为 ...(待续)

    java精典编程100例 33

    java 精典编程 100 例, author:朱千平 phone:13522080786 qq:200896066待续......

    (完整版)Java编程基础知识点汇总习题集--答案.doc

    Java 编程基础知识点汇总 一、Java 入门知识点汇总 1. Java 三大体系:Java SE(J2SE)、Java EE(J2EE)、Java ME(J2ME) * Java SE:标准版,包含 Java 最核心的类库 * Java EE:企业版,开发、装配...(待续)

    JAVA开发工程师精选面试题

    Java开发工程师精选面试题 本资源摘要信息主要是针对Java开发工程师面试的重要知识点,涵盖了Dubbo、ElasticSearch、JVM、多线程/高并发、消息中间件、SpringCloud等领域。 Dubbo相关知识点 1. Dubbo服务调用超时...

    java后端初级面试题

    JDK(Java Development Kit)是 Java 开发工具包,提供了编译、运行 Java 程序所需的各种工具和资源,包括 Java 编译器、Java 运行时环境,以及常用的 Java 类库等。 JRE(Java Runtime Environment)是 Java 运行...

    Java 开发工程师(初级)招聘试题

    本题未给出完整的代码示例,但从题目描述来看,主要考察考生对 Java 集合类的使用能力。通常情况下,可以使用 `ArrayList` 或 `LinkedList` 等集合类来存储 `Data` 类型的对象,并对其进行添加、删除、查找等操作。 ...

    线程池Demo(待续)

    线程池是Java多线程编程中一个非常重要的概念,它可以帮助我们有效地管理和控制并发执行的线程,提高系统的资源利用率并保持系统稳定性。在Java中,`java.util.concurrent`包提供了线程池的实现,如`ExecutorService...

    jd-gui,简单轻量的java反编译工具

    Java开发过程中,有时候我们需要查看和理解已编译的.class文件中的源代码,这对于逆向工程、调试或学习他人的代码非常有用。此时,就需要用到反编译工具,而jd-gui就是这样一款简单轻量的Java反编译工具。本文将深入...

    JDBC待续

    JDBC 是 Java 语言与数据库交互的一种标准接口,由 Sun Microsystems(现已被 Oracle 收购)开发,它允许 Java 程序通过 API 连接到各种类型的数据库系统,包括 MySQL、Oracle、SQL Server 等。JDBC 提供了连接、...

    java精典编程100例 43

    java 精典编程 100 例,待续...... author:朱千平 phone:13522080786 qq:200896066

    java精典编程100例 6

    java 精典编程 100 例,待续...... author:朱千平 phone:13522080786 qq:200896066

    java精典编程100例 26

    java 精典编程 100 例,待续...... author:朱千平 phone:13522080786 qq:200896066

Global site tag (gtag.js) - Google Analytics