精华内容
下载资源
问答
  • 容器

    2017-11-10 16:30:04
    容器数组:相同类型的有序集合,可以在...容器中的元素都为引用类型,不能放置原生数据类型(但是因为自动装箱,会把原生数据类型变成包装类) collection容器 set:不允许重复,使用自己的内部排列机制,重新排序 li

    容器

    数组:相同类型的有序集合,可以在其中放对象或者基本数据类型
    好处:是一种简单的线性序列,可以快速访问数组元素,效率高。从效率和类型检查的角度讲,数组最好
    坏处:容量需要事先确定,不能根据需求的变化扩容

    这里写图片描述

    • 分类
      容器中的元素都为引用类型,不能放置原生数据类型(但是因为自动装箱,会把原生数据类型变成包装类)
      • collection容器
        • set:不允许重复,使用自己的内部排列机制,重新排序
        • list:有序允许重复,以元素安插的次序来放置元素,不会重新排列
      • map容器
        • 保存键值对,不能有重复的key值,拥有自己的内部排序机制,重新排序
        • hashMap:无序,按照key的hashcode将值存入不同位置,key和value允许为null
        • hashtable:无序,线程安全,key和value不允许为null
        • linkedhashmap:有序
        • properties:hashtable子类,属性集合,key和value都是string
        • treemap:有序
        • weakhashmap:key值为弱引用,能被回收 -
    • 常用collection继承图谱
    • 常用collection继承图谱

    • 常用map继承图谱

    • 常用map继承图谱

    • 常用集合分类表

    • 常用集合分类表

    Collections类

    • 方法
      • addall(Collection

    Collection

    • 方法
      • add(E):加入元素
      • addall(Collection v):加入集合中的所有元素
      • clear():清空
      • contains(Object):包含判断
      • containsAll(Collection c):包含集合
      • equals(Object):相等判断
      • isEmpty():空判断
      • iterator():获取迭代器
      • remove(Object):移除元素
      • removeAll(Collection c):移除包含在集合中的所有元素
      • retainAll(Collection c):仅保留在集合中的元素
      • size():元素数
      • toArray():返回Object数组
      • toArray(T[] a):返回T类型数组

    容器总结与选用

    List接口对Collection进行了简单的扩充,它的具体实现类常用的有ArrayList和LinkedList。你可以将任何东西放到一个List容器中,并在需要时从中取出。ArrayList从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,而LinkedList的内部实现是链表,它适合于在链表中间需要频繁进行插入和删除操作。在具体应用时可以根据需要自由选择。前面说的Iterator只能对容器进行向前遍历,而ListIterator则继承了Iterator的思想,并提供了对List进行双向遍历的方法。

    Set接口也是Collection的一种扩展,而与List不同的时,在Set中的对象元素不能重复,也就是说你不能把同样的东西两次放入同一个Set容器中。它的常用具体实现有HashSet和TreeSet类。HashSet能快速定位一个元素,但是你放到HashSet中的对象需要实现hashCode()方法,它使用了前面说过的哈希码的算法。而TreeSet则将放入其中的元素按序存放,这就要求你放入其中的对象是可排序的,这就用到了集合框架提供的另外两个实用类Comparable和Comparator。一个类是可排序的,它就应该实现Comparable接口。有时多个类具有相同的排序算法,那就不需要在分别重复定义相同的排序算法,只要实现Comparator接口即可。集合框架中还有两个很实用的公用类:Collections和Arrays。Collections提供了对一个Collection容器进行诸如排序、复制、查找和填充等一些非常有用的方法,Arrays则是对一个数组进行类似的操作。

    Map是一种把键对象和值对象进行关联的容器,而一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。对于键对象来说,像Set一样,一个Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以键的唯一性很重要,也是符合集合的性质的。当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求。你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。Map有两种比较常用的实现:HashMap和TreeMap。HashMap也用到了哈希码的算法,以便快速查找一个键,TreeMap则是对键按序存放,因此它便有一些扩展的方法,比如firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。键和值的关联很简单,用pub(Object key,Object value)方法即可将一个键与一个值对象相关联。用get(Object key)可得到与此key对象所对应的值对象。

    2.List、vector、set、map的区别与联系
    总的说来,Java API中所用的集合类,都是实现了Collection接口,他的一个类继承结构如下:

    Collection<–List<–Vector
    Collection<–List<–ArrayList
    Collection<–List<–LinkedList
    Collection<–Set<–HashSet
    Collection<–Set<–HashSet<–LinkedHashSet
    Collection<–Set<–SortedSet<–TreeSet
    Vector : 基于Array的List,其实就是封装了Array所不具备的一些功能方便我们使用,它不可能走出Array的限制。性能也就不可能超越Array。所以,在可能的情况下,我们要多运用Array。另外很重要的一点就是Vector是“sychronized”的,这个也是Vector和ArrayList的唯一的区别。

    ArrayList:同Vector一样是一个基于Array上可自动扩展容量的集合,但是不同的是ArrayList不是同步的。所以在性能上要比Vector优越一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。

    LinkedList:不同于前面两种List,它不是基于Array的,所以不受Array性能的限制。它每一个节点(Node)都包含两方面的内容:1.节点本身的数据(data);2.下一个节点的信息(nextNode)。所以当对LinkedList做添加,删除动作的时候就不用像基于Array的List一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了。这就是LinkedList的优势。

    List总结:

    1. 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ];

    2. 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];

    3. 所有的List中可以有null元素,例如[ tom,null,1 ];

    4. 基于Array的List(Vector,ArrayList)适合查询,而LinkedList(链表)适合添加,删除操作。

    HashSet:虽然Set同List都实现了Collection接口,但是他们的实现方式却大不一样。List基本上都是以Array为基础。但是Set则是在HashMap的基础上来实现的,这个就是Set和List的根本区别。HashSet的存储方式是把HashMap中的Key作为Set的对应存储项。看看HashSet的add(Object obj)方法的实现就可以一目了然了。

    public boolean add(Object obj)
    {
    return map.put(obj, PRESENT) == null;
    }
    这个也是为什么在Set中不能像在List中一样有重复的项的根本原因,因为HashMap的key是不能有重复的。

    LinkedHashSet:HashSet的一个子类,一个链表。

    TreeSet:SortedSet的子类,它不同于HashSet的根本就是TreeSet是有序的。它是通过SortedMap来实现的。

    Set总结:

    1. Set实现的基础是Map(HashMap);

    2. Set中的元素是不能重复的,如果使用add(Object obj)方法添加已经存在的对象,则会覆盖前面的对象

    3. Java基本概念:集合类 List/Set/Map… 的区别和联系
      Collection:List、Set
      Map:HashMap、HashTable

    如何在它们之间选择

    一、Array , Arrays
    Java所有“存储及随机访问一连串对象”的做法,array是最有效率的一种。
    1、
    效率高,但容量固定且无法动态改变。
    array还有一个缺点是,无法判断其中实际存有多少元素,length只是告诉我们array的容量。
    2、、
    Java中有一个Arrays类,专门用来操作array。arrays中拥有一组static函数,
    equals():比较两个array是否相等。array拥有相同元素个数,且所有对应元素两两相等。
    fill():将值填入array中。
    sort():用来对array进行排序。
    binarySearch():在排好序的array中寻找元素。
    System.arraycopy():array的复制。

    二、Collection , Map
    若撰写程序时不知道究竟需要多少对象,需要在空间不足时自动扩增容量,则需要使用容器类库,array不适用。
    1、Collection 和 Map 的区别
    容器内每个为之所存储的元素个数不同。
    Collection类型者,每个位置只有一个元素。
    Map类型者,持有 key-value pair,像个小型数据库。
    2、各自旗下的子类关系
    Collection –List: 存入顺序即取出顺序
    –ArrayList / LinkedList / Vector
    –Set : 不能含有重复的元素,取出来的顺序可能和放入顺序不同
    –HashSet / TreeSet
    Map:将以特定次序存储元素。所以取出来的顺序可能和放入顺序不同
    –HashMap
    –HashTable
    –TreeMap
    3、其他特征
    * List,Set,Map将持有对象一律视为Object型别。
    * Collection、List、Set、Map都是接口,不能实例化。
    继承自它们的 ArrayList, Vector, HashTable, HashMap是具象class,这些才可被实例化。
    * vector容器确切知道它所持有的对象隶属什么型别。vector不进行边界检查。

    三、Collections
    Collections是针对集合类的一个帮助类。提供了一系列静态方法实现对各种集合的搜索、排序、线程完全化等操作。
    相当于对Array进行类似操作的类——Arrays。
    如,Collections.max(Collection coll); 取coll中最大的元素。
    Collections.sort(List list); 对list中元素排序
    四、如何选择?
    1、容器类和Array的区别、择取
    * 容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。
    * 一旦将对象置入容器内,便损失了该对象的型别信息。
    2、
    * 在各种Lists中,最好的做法是以ArrayList作为缺省选择。
    * 当插入、删除频繁时,使用LinkedList();
    Vector总是比ArrayList慢,所以要尽量避免使用。
    * 在各种Sets中,HashSet通常优于HashTree(插入、查找)。
    * 只有当需要产生一个经过排序的序列,才用TreeSet。
    HashTree存在的唯一理由:能够维护其内元素的排序状态。
    * 在各种Maps中
    HashMap用于快速查找。
    * 当元素个数固定,用Array,因为Array效率是最高的。

    注意:
    1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
    2、Set和Collection拥有一模一样的接口。
    3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)…。(add/get)
    4、一般使用ArrayList。
    用LinkedList构造堆栈stack、队列queue。
    5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
    HashMap会利用对象的hashCode来快速找到key。
    * hashing 哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个值存储在一个array中。
    我们都知道所有存储结构中,array查找速度是最快的。所以,可以加速查找。发生碰撞时,让array位置存储多个values。即,数组每个位置上又生成一个梿表。
    6、Map中元素,可以将key序列、value序列单独抽取出来。使用keySet()抽取key序列,将map中的所有keys生成一个Set。使用values()抽取value序列,将map中的所有values生成一个Collection。
    为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。

    展开全文
  • C++主要有两大场景,面向对象编程 OOP 和 泛型编程 GP,二者的主要区别是 OOP 会把数据和方法包装在一起,通过多层的继承关系来实现复杂的功能,而 GP 则会把数据和方法分开来,很少会有继承的关系。 STL 是 c++ 的...

    C++主要有两大场景,面向对象编程 OOP 和 泛型编程 GP,二者的主要区别是 OOP 会把数据和方法包装在一起,通过多层的继承关系来实现复杂的功能,而 GP 则会把数据和方法分开来,很少会有继承的关系。

    STL 是 c++ 的标准模板库,主要有 容器、分配器、算法、适配器、迭代器和函数对象等组成,设计之初就以 GP 为主,各类之间互相独立,比如容器和算法互相独立,通过迭代器来沟通;又比如各种容器之间并无直接的继承关系(早期)。

    2232dd29070906569d4588351def837f.png
    STL 六大组件及其关系

    容器是 STL 中最被人熟知的一部分,那么容器又是如何分类的呢?

    总的来说,容器可以分为序列容器和关联式容器。

    955a8530cb9a5b284225dc4d4e35e987.png
    一目了然

    序列容器有 array(c++11)、vector、deque、List 和 Forward_List 。

    array:定长数组,数组的包装类。

    vector:动态数组,满了之后二倍大小扩容

    deque:双向队列。其实现是一个分段式的连续存储,由一个 vector 作为基准, 数组中的元素都是指针, 指向每一个节点,数据存储在每个节点上,每个节点可以认为是一个数组。stack 和 queue 都是受限的 deque ,接口底部都是由 deque 实现,因此有人认为 stack 和 queue 不是容器,而是一种容器适配器 container adapter 。

    List:双向循环链表。

    Forward_List:单链表。

    关联式容器有 set / multiSet、 map / multiMap、 unordered set / multiSet、 unordered-map/multiMap 等。

    set / multiSet:红黑树实现,区别在于 set 中的元素是唯一的,multiSet 可以重复插入相同元素,同时不允许迭代器修改 set 中的元素,这一点是通过 const_iterator 实现的。底层是调用了 rbTree 的 unique_insert() 和 equal_insert()方法,这里可以看出,set 也是一种容器适配器。

    map / multiMap:也是由红黑树实现,和 set 的区别在于节点有 key/ data 组成,而 set 中的没有 data, 或者说 data 就是 key。类似的是,无法通过迭代器修改元素的 key ,但是可以修改 data。这点是通过在定义节点类型的时候,Pair<const keyType, dataType>,可见节点是一个 pair 类型,key 是常量无法修改。

    map 的[key]操作符会查找对应 key 的data,如果没有就会插入 key , 对应的 data 是默认值。因此也可以使用 [] 来插入数据,类似于先查找后 insert

    unordered set/map :基于哈希表实现,所以元素是无序的。桶子的个数默认是质数,比如53 97,采用链地址来解冲突。如果元素的个数大于桶的个数,就再散列。桶增长的速度类似于vector 的增长方式,2 倍增长,选择距离这个数最近的质数作为新的桶数。 stl 有一个写死的质数列表,增长的方式按照表的内容来增长。

    /*prime list*/
    

    ef5b093d2028452d8a7068f6c1bc32f3.png
    这个图更加直观,来自侯捷PPT。字节大小是32位机器下的size。

    上图中有缩进的代表衍生关系,并非继承,而是复合:类的内部有其他类的指针而已,比如 set 内部就有一个 rb_tree 的指针,这样做可以解耦。

    展开全文
  • 红色框起来的是C++11增加的东西,array由语言的数组包装成class。 Sequence Containers(序列式容器),会按放进去的顺序排列 array要多大有多大,严格限定的大小。vector起点不能动,后面可以自动增长,分配器可以...

    在这里插入图片描述
    红色框起来的是C++11增加的东西,array由语言的数组包装成class。
    Sequence Containers(序列式容器),会按放进去的顺序排列
    array要多大有多大,严格限定的大小。vector起点不能动,后面可以自动增长,分配器可以自动扩充。deque,两端可进可出,前面和后面都可以扩充。list,链表,指针串起来,双向的,环状链表。forward-list,单向链表,放一个分配一个。
    Associative Containers(关联式容器),有key/value,基于红黑树。
    各家编译器都用红黑树来做set/map。set的key就是value,value就是key,不分的。multiset/multimap可以重复,而set/map不能重复。
    Unordered Containers(不定序容器),位置会发生改变,基于哈希表。
    Separate Chaining能够避免碰撞(元素放进来位置冲突),用的最多解决hash表。链表太长也会重新打散。
    严格来说只有前面两类。
    测试程序的辅助函数

    using std::string;
    using std::cin;
    using std::cout;
    
    const long ASIZE = 1000000;  //多少个元素
    
    long get_a_target_long()  //获得输入的目标下标
    {
        long target = 0;
        cout << "target (0~" << RAND_MAX << "): ";
        cin >> target;
    	
        return target;
    }
    
    string get_a_target_string()  //获得目标的字符串,而不是数值,是为了体现指针和对象
    {
        long target = 0;
        char buf[10];
    
        cout << "target (0~" << RAND_MAX << "): ";
        cin >> target;
        snprintf(buf, 10, "%d", target);
        //sprintf(buf, "%d", target);
        
        return string(buf);
    }
    int compareLongs(const void* a, const void* b)  //比较大小
    {
        return (*(long*)a - *(long*)b);
    }
    
    int compareStrings(const void* a, const void* b)
    {
        if (*(string*)a > *(string*)b)
    	    return 1;
        else if(*(string*)a < *(string*)b)
    	    return -1;
        else
    	    return 0;
    }
    

    array测试:

    #include <string>
    #include <array>
    #include <iostream>
    #include <ctime>
    #include <cstdio>
    #include <cstdlib>  // qsort binarysreach, NULL
    
    #include "pub.h"
    
    using std::cin;
    using std::cout;
    using std::endl;
    using std::string;
    using std::array;
    
    namespace jj01
    {
    	void test_array()
    	{
    		cout << "\ntest_array()......... \n";
    
    		array<long, ASIZE> c;
    
    		//srand((unsigned)time(NULL));
    		clock_t timeStart = clock();
    		for (long i = 0; i < ASIZE; ++i) {
    		    c[i] = rand() % 65535;
    		}
    
    		cout << "milli-seconds:" << (clock() - timeStart) << endl;  //布置完数组需要多久
    		cout << "array.size()= " << c.size() << endl;
    		cout << "array.front()= " << c.front() << endl;  //首元素的大小
    		cout << "array.back()= " << c.back() << endl;  //最后一个元素的大小
    		cout << "array.data()= " << c.data() << endl;  //获取数组起点地址
    
    		long target = get_a_target_long();
    
    		timeStart = clock();
    		
    		cout << "-------------------before qsort: --------------" << endl;
    		
    		/*
    		for (long i = 0; i < ASIZE; ++i)
    		{
    		    cout << "The " << i << " element is:" << c[i] << endl;
    		}
    		*/
    
    		timeStart = clock();
    
    		qsort(c.data(), ASIZE, sizeof(long), compareLongs);  //最后一个参数定义如何比大小
    		
    		cout << "qsort(), milli-seconds: " << (clock() - timeStart) << endl;
    
    		cout << "---------------------after qsort:------------------ " << endl;
    
    		//timeStart = clock();
    		/*
    		for (long i = 0; i < ASIZE; ++i)
    		{
    		    cout << "The " << i << " element is:" << c[i] << endl;
    		}
    		*/
    
    
    		cout << "array.size()= " << c.size() << endl;
    		cout << "array.front()= " << c.front() << endl;
    		cout << "array.back()= " << c.back() << endl;
    		cout << "array.data()= " << c.data() << endl;
    
    		timeStart = clock();  //毫秒数,从起始到现在
    
    		long* pItem = (long*)bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);  //先排序后再去找元素。花费多久时间,排序花费时间久,寻值很快
    		cout << "bsearch(), milli-seconds: " << (clock() - timeStart) << endl;  //获得时间差
    		
    		if (pItem != NULL)
    			cout << "found, " << *pItem << endl;
    		else
    			cout << "not found!" << endl;
    	}
    }
    

    侯捷老师运行结果
    在这里插入图片描述

    展开全文
  • java并发容器

    2012-06-13 09:55:34
    java并发容器(Map、List、BlockingQueue) (2011-03-08 17:45:35)转载▼标签: java并发容器maplistblockingqueue杂谈 分类: 架构与开发 Java库本身就有多种线程安全的容器和同步工具,其中同步容器包括两部分:...
    java并发容器(Map、List、BlockingQueue) (2011-03-08 17:45:35)转载▼标签: java并发容器maplistblockingqueue杂谈 分类: 架构与开发  

    Java库本身就有多种线程安全的容器和同步工具,其中同步容器包括两部分:一个是Vector和Hashtable。另外还有JDK1.2中加入的同步包装类,这些类都是由Collections.synchronizedXXX工厂方法。同步容器都是线程安全的,但是对于复合操作,缺有些缺点:

    ① 迭代:在查觉到容器在迭代开始以后被修改,会抛出一个未检查异常ConcurrentModificationException,为了避免这个异常,需要在迭代期间,持有一个容器锁。但是锁的缺点也很明显,就是对性能的影响。

    ② 隐藏迭代器:StringBuilder的toString方法会通过迭代容器中的每个元素,另外容器的hashCode和equals方法也会间接地调用迭代。类似地,contailAll、removeAll、retainAll方法,以及容器作为参数的构造函数,都会对容器进行迭代。

    ③ 缺少即加入等一些复合操作



    public static Object getLast(Vector list) {

    int lastIndex = list.size() - 1;

    return list.get(lastIndex);

    }

    public static void deleteLast(Vector list) {

    int lastIndex = list.size() - 1;

    list.remove(lastIndex);

    }

    getLast和deleteLast都是复合操作,由先前对原子性的分析可以判断,这依然存在线程安全问题,有可能会抛出ArrayIndexOutOfBoundsException的异常,错误产生的逻辑如下所示:




    解决办法就是通过对这些复合操作加锁


    1 并发容器类


    正是由于同步容器类有以上问题,导致这些类成了鸡肋,于是Java 5推出了并发容器类,Map对应的有ConcurrentHashMap,List对应的有CopyOnWriteArrayList。与同步容器类相比,它有以下特性:



    1.1 ConcurrentHashMap


    · 更加细化的锁机制。同步容器直接把容器对象做为锁,这样就把所有操作串行化,其实这是没必要的,过于悲观,而并发容器采用更细粒度的锁机制,名叫分离锁,保证一些不会发生并发问题的操作进行并行执行

    · 附加了一些原子性的复合操作。比如putIfAbsent方法

    · 迭代器的弱一致性,而非“及时失败”。它在迭代过程中不再抛出Concurrentmodificationexception异常,而是弱一致性。

    · 在并发高的情况下,有可能size和isEmpty方法不准确,但真正在并发环境下这些方法也没什么作用。

    · 另外,它还有一些附加的原子操作,缺少即加入、相等便移除、相等便替换。



    putIfAbsent(K key, V value),缺少即加入(如果该键已经存在,则不加入)
    如果指定键已经不再与某个值相关联,则将它与给定值关联。

    类似于下面的操作

    If(!map.containsKey(key)){

    return map.put(key,value);

    }else{

    return map.get(key);

    }



    remove(Object key, Object value),相等便移除
    只有目前将键的条目映射到给定值时,才移除该键的条目。

    类似于下面的:

    if(map.containsKey(key) && map.get(key).equals(value)){

    Map.remove();

    return true;

    }else{

    return false;

    }



    replace(K key, V value)

    replace(K key, V oldValue, V newValue),相等便替换。
    只有目前将键的条目映射到某一值时,才替换该键的条目。



    上面提到的三个,都是原子的。在一些缓存应用中可以考虑代替HashMap/Hashtable。



    1.2 CopyOnWriteArrayList和CopyOnWriteArraySet
    · CopyOnWriteArrayList采用写入时复制的方式避开并发问题。这其实是通过冗余和不可变性来解决并发问题,在性能上会有比较大的代价,但如果写入的操作远远小于迭代和读操作,那么性能就差别不大了。



    应用它们的场合通常在数组相对较小,并且遍历操作的数量大大超过可变操作的数量时,这种场合应用它们非常好。它们所有可变的操作都是先取得后台数组的副本,对副本进行更改,然后替换副本,这样可以保证永远不会抛出ConcurrentModificationException移除。

    2 队列
    Java中的队列接口就是Queue,它有会抛出异常的add、remove方法,在队尾插入元素以及对头移除元素,还有不会抛出异常的,对应的offer、poll方法。



    2.1 LinkedList
    List实现了deque接口以及List接口,可以将它看做是这两种的任何一种。



    Queue queue=new LinkedList();

    queue.offer("testone");

    queue.offer("testtwo");

    queue.offer("testthree");

    queue.offer("testfour");



    System.out.println(queue.poll()); //testone

    2.2 PriorityQueue
    一个基于优先级堆(简单的使用链表的话,可能插入的效率会比较低O(N))的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。优先级队列不允许使用 null 元素。依靠自然顺序的优先级队列还不允许插入不可比较的对象。



    queue=new PriorityQueue();

    queue.offer("testone");

    queue.offer("testtwo");

    queue.offer("testthree");

    queue.offer("testfour");



    System.out.println(queue.poll()); //testfour



    2.3 ConcurrentLinkedQueue
    基于链节点的,线程安全的队列。并发访问不需要同步。在队列的尾部添加元素,并在头部删除他们。所以只要不需要知道队列的大小,并发队列就是比较好的选择。







    3 阻塞队列
    3.1 生产者和消费者模式
    生产者和消费者模式,生产者不需要知道消费者的身份或者数量,甚至根本没有消费者,他们只负责把数据放入队列。类似地,消费者也不需要知道生产者是谁,以及是谁给他们安排的工作。



    而Java知道大家清楚这个模式的并发复杂性,于是乎提供了阻塞队列(BlockingQueue)来满足这个模式的需求。阻塞队列说起来很简单,就是当队满的时候写线程会等待,直到队列不满的时候;当队空的时候读线程会等待,直到队不空的时候。实现这种模式的方法很多,其区别也就在于谁的消耗更低和等待的策略更优。以LinkedBlockingQueue的具体实现为例,它的put源码如下:

    public void put(E e) throws InterruptedException {

    if (e == null) throw new NullPointerException();

    int c = -1;

    final ReentrantLock putLock = this.putLock;

    final AtomicInteger count = this.count;

    putLock.lockInterruptibly();

    try {



    try {

    while (count.get() == capacity)

    notFull.await();

    } catch (InterruptedException ie) {

    notFull.signal();

    // propagate to a non-interrupted thread

    throw ie;

    }

    insert(e);

    c = count.getAndIncrement();

    if (c + 1 < capacity)

    notFull.signal();

    } finally {

    putLock.unlock();

    }

    if (c == 0)

    signalNotEmpty();

    }



    撇开其锁的具体实现,其流程就是我们在操作系统课上学习到的标准生产者模式,看来那些枯燥的理论还是有用武之地的。其中,最核心的还是Java的锁实现,有兴趣的朋友可以再进一步深究一下。



    阻塞队列Blocking queue,提供了可阻塞的put和take方法,他们与可定时的offer和poll方法是等价。Put方法简化了处理,如果是有界队列,那么当队列满的时候,生成者就会阻塞,从而改消费者更多的追赶速度。







    3.2 ArrayBlockingQueue和LinkedBlockingQueue


    FIFO的队列,与LinkedList(由链节点支持,无界)和ArrayList(由数组支持,有界)相似(Linked有更好的插入和移除性能,Array有更好的查找性能,考虑到阻塞队列的特性,移除头部,加入尾部,两个都区别不大),但是却拥有比同步List更好的并发性能。



    另外,LinkedList永远不会等待,因为他是无界的。



    BlockingQueue<String> queue=new ArrayBlockingQueue<String>(5);



    Producer p=new Producer(queue);

    Consumer c1=new Consumer(queue);

    Consumer c2=new Consumer(queue);



    new Thread(p).start();

    new Thread(c1).start();

    new Thread(c2).start();





    class Producer implements Runnable {

    private final BlockingQueue queue;

    Producer(BlockingQueue q) { queue = q; }



    public void run() {

    try {

    for(int i=0;i<100;i++){

    queue.put(produce());

    }



    } catch (InterruptedException ex) {}

    }



    String produce() {

    String temp=""+(char)('A'+(int)(Math.random()*26));

    System.out.println("produce"+temp);

    return temp;

    }

    }





    class Consumer implements Runnable {

    private final BlockingQueue queue;

    Consumer(BlockingQueue q) { queue = q; }

    public void run() {

    try {

    for(int i=0;i<100;i++){

    consume(queue.take());

    }

    } catch (InterruptedException ex) {}

    }

    void consume(Object x) {

    System.out.println("cousume"+x.toString());

    }

    }



    输出:

    produceK

    cousumeK

    produceV

    cousumeV

    produceQ

    cousumeQ

    produceI

    produceD

    produceI

    produceG

    produceA

    produceE

    cousumeD

    3.3 PriorityBlockingQueue
    一个按优先级堆支持的无界优先级队列队列,如果不希望按照FIFO的顺序进行处理,它非常有用。它可以比较元素本身的自然顺序,也可以使用一个Comparator排序。

    3.4 DelayQueue
    一个优先级堆支持的,基于时间的调度队列。加入到队列中的元素必须实现新的Delayed接口(只有一个方法,Long getDelay(java.util.concurrent.TimeUnit unit)),添加可以理立即返回,但是在延迟时间过去之前,不能从队列中取出元素,如果多个元素的延迟时间已到,那么最早失效链接/失效时间最长的元素将第一个取出。



    static class NanoDelay implements Delayed{

    long tigger;



    NanoDelay(long i){

    tigger=System.nanoTime()+i;

    }



    public boolean equals(Object other){

    return ((NanoDelay)other).tigger==tigger;

    }





    public long getDelay(TimeUnit unit) {

    long n=tigger-System.nanoTime();

    return unit.convert(n, TimeUnit.NANOSECONDS);

    }



    public long getTriggerTime(){

    return tigger;

    }





    public int compareTo(Delayed o) {

    long i=tigger;

    long j=((NanoDelay)o).tigger;

    if(i<j){

    return -1;

    }

    if(i>j)

    return 1;

    return 0;

    }



    }



    public static void main(String[] args) throws InterruptedException{

    Random random=new Random();

    DelayQueue<NanoDelay> queue=new DelayQueue<NanoDelay>();

    for(int i=0;i<5;i++){

    queue.add(new NanoDelay(random.nextInt(1000)));



    }

    long last=0;

    for(int i=0;i<5;i++){

    NanoDelay delay=(NanoDelay)(queue.take());

    long tt=delay.getTriggerTime();

    System.out.println("Trigger time:"+tt);



    if(i!=0){

    System.out.println("Data: "+(tt-last));

    }

    last=tt;

    }



    }





    3.5 SynchronousQueue
    不是一个真正的队列,因为它不会为队列元素维护任何存储空间,不过它维护一个排队的线程清单,这些线程等待把元素加入(enqueue)队列或者移出(dequeue)队列。也就是说,它非常直接的移交工作,减少了生产者和消费者之间移动数据的延迟时间,另外,也可以更快的知道反馈信息,当移交被接受时,它就知道消费者已经得到了任务。

    因为SynChronousQueue没有存储的能力,所以除非另一个线程已经做好准备,否则put和take会一直阻止。它只有在消费者比较充足的时候比较合适。



    4 双端队列(Deque)
    JAVA6中新增了两个容器Deque和BlockingDeque,他们分别扩展了Queue和BlockingQueue。Deque它是一个双端队列,允许高效的在头和尾分别进行插入和删除,它的实现分别是ArrayDeque和LinkedBlockingQueue。



    双端队列使得他们能够工作在一种称为“窃取工作”的模式上面。



    5 最佳实践
    1..同步的(synchronized)+HashMap,如果不存在,则计算,然后加入,该方法需要同步。

    HashMap cache=new HashMap();

    public synchronized V compute(A arg){

    V result=cace.get(arg);

    Ii(result==null){

    result=c.compute(arg);

    Cache.put(result);

    }

    Return result;

    }





    2.用ConcurrentHashMap代替HashMap+同步.,这样的在get和set的时候也基本能保证原子性。但是会带来重复计算的问题.

    Map<A,V> cache=new ConcurrentHashMap<A,V>();

    public V compute(A arg){

    V result=cace.get(arg);

    Ii(result==null){

    result=c.compute(arg);

    Cache.put(result);

    }

    Return result;

    }

    3.采用FutureTask代替直接存储值,这样可以在一开始创建的时候就将Task加入

    Map<A,FutureTask<V>> cache=new ConcurrentHashMap<A,FutureTask<V>>();

    public V compute(A arg){

    FutureTask <T> f=cace.get(arg);

    //检查再运行的缺陷

    Ii(f==null){

    Callable<V> evel=new Callable(){

    Public V call() throws ..{

    return c.compute(arg);

    }

    };

    FutureTask <T> ft=new FutureTask<T>(evel);

    f=ft;

    cache.put(arg,ft;

    ft.run();

    }

    Try{

    //阻塞,直到完成

    return f.get();

    }cach(){

    }

    }



    4.上面还有检查再运行的缺陷,在高并发的情况下啊,双方都没发现FutureTask,并且都放入Map(后一个被前一个替代),都开始了计算。



    这里的解决方案在于,当他们都要放入Map的时候,如果可以有原子方法,那么已经有了以后,后一个FutureTask就加入,并且启动。

    public V compute(A arg){

    FutureTask <T> f=cace.get(arg);

    //检查再运行的缺陷

    Ii(f==null){

    Callable<V> evel=new Callable(){

    Public V call() throws ..{

    return c.compute(arg);

    }

    };

    FutureTask <T> ft=new FutureTask<T>(evel);

    f=cache.putIfAbsent(args,ft); //如果已经存在,返回存在的值,否则返回null

    if(f==null){f=ft;ft.run();} //以前不存在,说明应该开始这个计算

    else{ft=null;} //取消该计算

    }

    Try{

    //阻塞,直到完成

    return f.get();

    }cach(){

    }

    }



    5.上面的程序上来看已经完美了,不过可能带来缓存污染的可能性。如果一个计算被取消或者失败,那么这个键以后的值永远都是失败了;一种解决方案是,发现取消或者失败的task,就移除它,如果有Exception,也移除。





    6.另外,如果考虑缓存过期的问题,可以为每个结果关联一个过去时间,并周期性的扫描,清除过期的缓存。(过期时间可以用Delayed接口实现,参考DelayQueue,给他一个大于当前时间XXX的时间,,并且不断减去当前时间,直到返回负数,说明延迟时间已到了。)





    Java集合容器总结。
    按数据结构主要有以下几类:
    1,内置容器:数组
    2,list容器:Vetor,Stack,ArrayList,LinkedList,
    CopyOnWriteArrayList(1.5),AttributeList(1.5),RoleList(1.5),RoleUnresolvedList(1.5),
    ConcurrentLinkedQueue(1.5),ArrayBlockingQueue(1.5),LinkedBlockingQueue(1.5),
    PriorityQueue(1.5),PriorityBlockingQueue(1.5),SynchronousQueue(1.5)
    3,set容器:HashSet(1.2),LinkedHashSet(1.4),TreeSet(1.2),
    CopyOnWriteArraySet(1.5),EnumSet(1.5),JobStateReasons。
    4,map容器:Hashtable,HashMap(1.2),TreeMap(1.2),LinkedHashMap(1.4),WeakHashMap(1.2),
    IdentityHashMap(1.4),ConcurrentMap(1.5),concurrentHashMap(1.5)。
    Set 接口继承 Collection,但不允许重复,使用自己内部的一个排列机制。
    List 接口继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。
    Map接口是一组成对的键-值对象,即所持有的是key-value pairs。Map中不能有重复的key。拥有自己的内部排列机制。
    按新旧主要有以下几类:
    Java1.2前的容器:Vector,Stack,Hashtable。
    Java1.2的容器:HashSet,TreeSet,HashMap,TreeMap,WeakHashMap
    Java1.4的容器:LinkedHashSet,LinkedHashMap,IdentityHashMap,ConcurrentMap,concurrentHashMap
    java1.5新增:CopyOnWriteArrayList,AttributeList,RoleList,RoleUnresolvedList,
    ConcurrentLinkedQueue,ArrayBlockingQueue,LinkedBlockingQueue,PriorityBlockingQueue
    ArrayBlockingQueue,CopyOnWriteArraySet,EnumSet,
    未知:JobStateReasons
    按线程安全主要有以下几类:
    线程安全
    一,使用锁:
    完全不支持并发:
    list容器:Vetor,Stack,CopyOnWriteArrayList,ArrayBlockingQueue,
    LinkedBlockingQueue,PriorityBlockingQueue,SynchronousQueue
    set容器:CopyOnWriteArraySet
    map容器:Hashtable
    部分支持并发:
    list容器:无
    set容器:无
    map容器:concurrentHashMap
    使用非阻塞算法:
    list容器:ConcurrentLinkedQueue
    set容器:无
    map容器:无
    二,非线程安全:
    list容器:ArrayList,LinkedList,AttributeList,RoleList,RoleUnresolvedList,PriorityQueue
    set容器:HashSet,TreeSet,LinkedHashSet,EnumSet
    map容器:HashMap,TreeMap,LinkedHashMap,WeakHashMap,IdentityHashMap,EnumMap
    按遍历安全主要有以下几类:
    一,遍历安全:
    可并发遍历:
    list容器:CopyOnWriteArrayList,ConcurrentLinkedQueue
    set容器:CopyOnWriteArraySet,EnumSet,EnumMap
    map容器:无
    不可并发遍历:
    list容器:Vetor,Stack,Hashtable,ArrayBlockingQueue,
    LinkedBlockingQueue,PriorityBlockingQueue,SynchronousQueue
    set容器:无
    map容器:Hashtable,concurrentHashMap
    注意1:concurrentHashMap迭代器它们不会抛出ConcurrentModificationException。不过,迭代器被设计成每次仅由一个线程使用。
    二,遍历不安全:
    会抛异常ConcurrentModificationException:
    list容器:ArrayList,LinkedList,AttributeList,RoleList,RoleUnresolvedList
    set容器:HashSet,TreeSet,TreeSet,LinkedHashSet
    map容器:HashMap,TreeMap,LinkedHashMap,WeakHashMap,IdentityHashMap
    注意1:返回的迭代器是弱一致 的:它们不会抛出 ConcurrentModificationException,
    也不一定显示在迭代进行时发生的任何映射修改的效果的容器有:
    EnumSet,EnumMap
    按遍历是否有序性分类
    存储数据有序:
    list容器: ConcurrentLinkedQueue(1.5),ArrayBlockingQueue(1.5),LinkedBlockingQueue(1.5),
    SynchronousQueue(1.5)
    set容器:TreeSet(1.2).(他们实现了set接口),
    CopyOnWriteArraySet(1.5),EnumSet(1.5),JobStateReasons。
    map容器:TreeMap(1.2),LinkedHashMap(1.4) 。
    一定规则下存储数据有序:
    list容器:Stack,Vetor,ArrayList,LinkedList,CopyOnWriteArrayList(1.5),AttributeList(1.5),RoleList(1.5),RoleUnresolvedList(1.5)
    set容器:无
    map容器:无
    遍历无序但移除有序:
    list容器:PriorityQueue(1.5),PriorityBlockingQueue(1.5)
    set容器:无
    map容器:无
    无论如何都无序:
    list容器:无
    set容器:HashSet(1.2),LinkedHashSet(1.4)
    map容器:Hashtable,HashMap(1.2),WeakHashMap(1.2),IdentityHashMap(1.4),
    ConcurrentMap(1.5),concurrentHashMap(1.5)
    可以按自然顺序(参见 Comparable)或比较器进行排序的有:
    list容器:PriorityQueue(1.5),PriorityBlockingQueue
    set容器:TreeSet(1.2)
    map容器:TreeMap(1.2)
    实现了RandomAccess接口的有:
    ArrayList, AttributeList, CopyOnWriteArrayList, RoleList, RoleUnresolvedList, Stack, Vector
    RandomAccess接口是List 实现所使用的标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
    在对List特别的遍历算法中,要尽量来判断是属于 RandomAccess(如ArrayList)还是SequenceAccess(如LinkedList),
    因为适合RandomAccess List的遍历算法,用在SequenceAccess List上就差别很大,
    即对于实现了RandomAccess接口的类实例而言,此循环
    for (int i=0, i<list.size(); i++)
    list.get(i);
    的运行速度要快于以下循环:
    for (Iterator i=list.iterator(); i.hasNext(); )
    i.next();
    展开全文
  • 容器分类: 容器总体上可分为3种:序列式容器、关联式容器、无序容器。 1、序列式容器 sequence containers: Array,C++11,就是对数组的包装,大小固定; Vector,内存不够可以在后边自动增长; Deque...
  • 1.nn.Sequetial:按顺序包装多个网络层(使用容器的时候,容器里面的model属于容器,而这个容器属于本网络)注意哦,这个容器后面括号里都是参数所以要用逗号隔开 eg#我们习惯将卷积层池化层认为是特征提取部分,全连接...
  • 食品包装学 第三章

    2021-01-21 09:20:58
    第三章 食品包装用塑料材料及其制品第一节 塑料的组成、分类和主要包装性能指标第三节 软塑包装材料第四节 塑料包装容器及制品第二节 食品包装用塑料本章学习目标1、掌握塑料基本概念、组成及主要性
  • 包装学科的分类比较多样,通常将其分类包装材料学、包装运输学、包装工艺学、包装设计学、包装管理学、包装装饰学、包装测试学、包装机械学等分学科。目前,中国已有40多所高校开办了包装工程专业?..
  • java集合框架 框架设计理念 容器 继承层级结构 继承图 集合框架中的抽象类 主要的实现类 实现类特性 集合框架分类 集合框架并发包 并发实现类 什么是容器? 由一个或多个确定的元素所构成的整体叫做集合。 容器...
  • 垃圾分类建美好城市——践行社会主义核心价值观,目录:厨余垃圾、可回收垃圾、有害垃圾、其他垃圾,可回收物就是可以再生循环的垃圾物,包括纸类,硬纸板,塑料包装,玻璃等一系列物品;厨余垃圾源于居民日常生活及...
  • 包装是工厂中重复且单调的工作,环节中任务类型包括分层包装、分拣和包装分类、装袋,任务的多样性要求操作人员能够对生产线和当前环境中的频繁更改做出响应。此外,市场变化,例如减少批次数量和增加产品多样性,...
  • java集合框架 框架设计理念 容器 继承层级结构 继承图 集合框架中的抽象类 主要的实现类 实现类特性 集合框架分类 集合框架并发包 并发实现类 什么是容器? 由一个或多个确定的元素所构成的整体叫做集合。 容器用来...
  • 一般的过滤器的分类如下: 请求过滤器 安全检查 格式化请求首部 请求审计和日志 响应过滤器 压缩响应流 追加响应流 创建不同的响应流 和Servlet一样,过滤器也和容器密切相关: 容器知道过滤器的API 容器...
  • 一个使用的简单示例(软件包文档)和一个模型对图像进行分类。 获取模型文件 wget https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip unzip inception5h.zip 发展 GoCV是使用cgo围绕...
  • C++11新特性(三) 一、智能指针  1、auto_ptr指针  2、shared_ptr指针  3、unique_ptr指针  4、weak_ptr指针 ... 5、weak_ptr指针解决... 1、C++11 STL容器分类  2、array  3、forward_list  4、uno...
  • GUI : String,包装器,集合,泛型,反射 GridLayout : 网格布局 new GridLayout(3,3); CardLayout : 卡片布局 每次添加到容器中的组件,当成卡片, JPanel pan= new JPanel(); CardLayout c = new CardLayout(); ...
  • 文章目录一、集合框架基本概念二、集合框架基本分类三、JAVA包装类四、Collection接口五、Iterator接口 一、集合框架基本概念 集合是长度可变的用于存取数据的容器,可以存储不同类型的对象,存储的都是对象的引用...
  • stack和queue

    2021-04-14 19:39:41
    文章目录1.栈和队列常用接口2.容器适配器3.deque3.1是什么3.2deque的优缺点3.3deque作为stack和queue的...stack和queue,就是容器适配器,因为stack和queue只是对其它容器的接口进行了包装,STL中stack和queue默认使
  • exoplanet-spectra-源码

    2021-03-30 21:07:57
    包装概述 generate_data.py 生成综合数据集 grid_search.py 超参数调整 classifier.py 所有分类器的父类。 容器功能,用于评估预测 机器学习算法 线性判别分析(LDA) K最近邻居(KNN) 分类和回归树(CART) ...
  •  集合时一种容器,长度可变,可以存储任意类型的对象,基本数据类型也能够装入,是因为其内部是先自动装箱包装包装类对象,然后存入集合的;  对比数组:也是容器,长度固定,只能存储基本数据类型 二、集合...
  • 数组的基本定义

    2018-11-25 16:48:40
    数组要经过包装分类分类是一种行为,行为不能直接被引用,需要new出来。 语法:数据类型[]数组名=new 数据类型[长度]; 数据类型[]数组名=new 数据类型[]{值1,值2...}; 数据类型[]数组名={值1,值2...};Stri....
  • 常用集合整理笔记

    2021-01-12 17:09:07
    存储基本数据类型会自动装箱变成包装类对象. 分类 Collection集合:单列集合; List集合:有序可重复 Set集合:无序不可重复 Map集合:单列集合 常用方法: add(E) add(index,E) 添加元素 remove(index) remove(E) 删除...
  • 收集和贮存,常见违法行为 1、车间临时收集危险废物的设施未张贴危险废物...7、危险废物贮存场所未设施危险废物识别标志,包装容器上未张贴标签。8、将一般固废和危险废物混合储存,未做到分类储存。 9、危险废物...
  • ​​收集和贮存,常见违法行为​1、车间临时收集危险废物的设施未张贴危险废物...7、危险废物贮存场所未设施危险废物识别标志,包装容器上未张贴标签。8、将一般固废和危险废物混合储存,未做到分类储存。 9、危险...
  • JAVA数组

    2018-11-21 20:50:17
    1.数组 概念:用于在内存中存储一组相同类型的单个数据容器... 附:数组要经过包装分类分类是一种行为。行为不能直接引用,需要new出来。 数据类型[] 数组名=new 数据类型[]{值1,值2,值3.......}; String...
  • 铝下游消费结构分布主要用于建筑地产、电子电力、交通运输、耐用消费品、机械设备、包装容器等,占比分别为 40%、16%、14%、13%、7%、6%。 全球原铝需求增速从2013年的9.2%高位震荡回落,2018年消费量6570万吨,同比...
  • 这一节介绍表单设计器的常用控件的设计。  在前面两章节的附图中我已经给出了表单控件的两大分类:区域控件、常用控件。...这三个控件是我们的其他控件的容器或者叫包装器,相当于VS里面的各种Panel...

空空如也

空空如也

1 2 3 4 5
收藏数 84
精华内容 33
关键字:

包装容器分类