Java 数组集合(三)

104 篇文章 0 订阅

Java 数组集合(一)List
Java 数组集合(二)Set

Map

HashMap

HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。HashMap最多允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,及任意时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。

ConcurrentHashMap

Segment

ConcurrentHashMap和Hash Map类似,但是ConcurrentHashMap能够支持并发操作,所以要复杂一点。整个ConcurrentHashMap有一个个Segment组成,Segment代表“部分”或“一段”的意思,所以很多地方都会将其描绘为分段锁。

线程安全

ConcurrentHashMap是一个Segment数组,Segment通过继承ReentrantLock来进行加锁,所以每次需要加锁的操作锁住的是一个Segment,这样只要保证每个Segment是线程安全的,也就实现了全局的线程安全。
并发度

concurrencyLevel:

并行级别、并发数、Segment数,默认是16.

import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

public class ConcurrentHashMapTest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		// 创建
		ConcurrentHashMap<Integer, String> chm = new ConcurrentHashMap<Integer, String>();
		CountDownLatch countDownLatch = new CountDownLatch(2);
		Runnable runnable = () -> {
			for (int i = 1; i < 5; i++) {
				String value = chm.get(i);
				if (value == null) {
					value=""+i;
					chm.put(i, value);
				} else {
					chm.put(i, value + 1);
				}
			}

			countDownLatch.countDown();
		};

		// 两个线程操作同一个key,可能会出现覆盖的现象,导致key的值小于10
		new Thread(runnable).start();
		new Thread(runnable).start();

		countDownLatch.await();
		System.out.println(chm);

	}

	// 基本操作
	public static void ConcurrentHashMap_Test(ConcurrentHashMap<Integer, String> chm) {
		// 添加
		for (int i = 65; i < 91; i++) {
			String str = "" + (char) i;
			chm.put(i, str);
		}
		// size()
		System.out.println("size = " + chm.size());
		// 输出
		System.out.println("遍历");
		for (Entry<Integer, String> entry : chm.entrySet()) {
			if (entry.getKey() > 77) {
				Integer key = entry.getKey();
				String value = entry.getValue();
				System.out.print(key + " => " + value);
				System.out.println();
			}
		}
	}

}

HashTable

HashTable是遗留类,很多映射的常用功能与HashMap类似,不同的是它承自Dictionary类,并且是线程安全的,任意时刻只有一个线程能够改写HashTable,并发性不如ConcurrentHashMapp,因为ConcurrentHashMap引入了分段锁。HashTable不建议在新代码使用,不需要线程安全的场合可以用HashTable替换,需要线程安全的场合可以用ConcurrentHashMap替换。

import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

public class HashTableTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Hashtable<Integer, String> ht = new Hashtable<Integer, String>();
		// HashTable_Test(ht);
		// HashTable_Sort(ht);
		HashTable_T(ht);

	}

	// 多线程
	public static void HashTable_T(Hashtable<Integer, String> ht) {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					ht.put(i, "thread value" + i);
					try {
						Thread.sleep(new Random().nextInt(1));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});

		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					synchronized (ht) {// 迭代必须同步
						if (ht.size() > 0) {
							for (Map.Entry entry : ht.entrySet()) {
								System.out.println(entry.getKey() + " => " + entry.getValue());
							}
						}
						try {
							Thread.sleep(new Random().nextInt(100));
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		});

		thread.start();
		thread2.start();
	}

	// 排序
	public static void HashTable_Sort(Hashtable<Integer, String> ht) {
		ht.put(5, "EE");
		ht.put(22, "QQ");
		ht.put(26, "ZZ");
		ht.put(3, "CC");
		ht.put(7, "GG");
		ht.put(1, "AA");
		System.out.println(ht);
	}

	// 基本操作
	public static void HashTable_Test(Hashtable<Integer, String> ht) {
		// 添加
		for (int i = 65; i < 91; i++) {
			String str = "" + (char) i;
			ht.put(i, str);
		}
		// size()
		System.out.println("size = " + ht.size());
		// 输出
		System.out.println("遍历");
		for (Entry<Integer, String> entry : ht.entrySet()) {
			if (entry.getKey() < 88) {
				Integer key = entry.getKey();
				String value = entry.getValue();
				System.out.print(key + " => " + value);
				System.out.println();
			}
		}
	}

}

TreeMap

TreeMap实现SortedMap接口,能够把它保存的纪录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排序过的。在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出ClassCatException类型的异常。

import java.util.TreeMap;
import java.util.Map.Entry;

public class TreeMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 创建
		TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
		//
		// TreeMap_Test(tm);
		

	}
	

	// 基本操作
	public static void TreeMap_Test(TreeMap<Integer, String> tm) {
		// 添加
		for (int i = 65; i < 91; i++) {
			String str = "" + (char) i;
			tm.put(i, str);
		}
		// size()
		System.out.println("size = " + tm.size());
		// 输出
		System.out.println("遍历");
		for (Entry<Integer, String> entry : tm.entrySet()) {
			if (entry.getKey() < 88) {
				Integer key = entry.getKey();
				String value = entry.getValue();
				System.out.print(key + " => " + value);
				System.out.println();
			}
		}
	}

	//Person
	public static void TreeMap_Person() {
		TreeMap<Integer, Person> tmp = new TreeMap<Integer, Person>();
		for (int i = 0; i < 30; i++) {
			int age = (int) (Math.random() * 20 + 1);
			String name = "" + (char) (int) (Math.random() * 90 + 64);
			tmp.put(i, new Person(name, age));
		}

		for (Entry<Integer, Person> entry : tmp.entrySet()) {
			Integer key = entry.getKey();
			Person value = entry.getValue();
			System.out.print(key + " => " + value);
			System.out.println();
		}
	}
}

class Person implements Comparable<Object> {
	private String name;
	private int age;

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int compareTo(Object o) {
		// TODO Auto-generated method stub
		Person person = (Person) o;
		if (this.age > person.age) {
			return 1;
		}
		if (this.age < person.age) {
			return -1;
		}

		return this.name.compareTo(person.name);
	}

}

LinkedHashMap

LinkedHashMap是HashMap的一个子类,保存了记录的插入顺序,在使用Iterator遍历LinkedHashMap时,先得到的纪录肯定是先插入的,也可以在构造时带参数,按照访问次序排序。

import java.util.LinkedHashMap;
import java.util.Map.Entry;

public class LinkedHashMapTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 创建
		LinkedHashMap<Integer, String> lhm = new LinkedHashMap<Integer, String>();
		LinkedHashMap_Test(lhm);

	}
	// 基本操作
		public static void LinkedHashMap_Test(LinkedHashMap<Integer, String> lhm) {
			// 添加
			for (int i = 65; i < 91; i++) {
				String str = "" + (char) i;
				lhm.put(i, str);
			}
			// size()
			System.out.println("size = " + lhm.size());
			// 输出
			System.out.println("遍历");
			for (Entry<Integer, String> entry : lhm.entrySet()) {
				if (entry.getKey() < 88) {
					Integer key = entry.getKey();
					String value = entry.getValue();
					System.out.print(key + " => " + value);
					System.out.println();
				}
			}
		}

}

LRU(Least Recently Used):

LRU:最近最久未使用策略,优先淘汰最久未使用的数据,也就是上次被访问时间距离现在最久的数据。该策略可以保证内存中的数据都是热点数据,也就是经常被访问的数据,从而保证缓存命中率。

使用LinkedHashMap实现

LinkedHashMap底层就是用的【HashMap】加【双链表】实现的,而且本身已经实现了按照访问顺序的存储。此外,LinkedHashMap中本身就实现了一个方法removeEldestEntry用于判断是否需要移除最不常读取的数,方法默认是直接返回false,不会移除元素,所以需要【重写该方法】,即当缓存满后就移除最不常用的数。

HashMap、ConcurrentHashMap、HashTable、TreeMap、LinkedHashMap

  1. HashMap、TreeMap、LinkHashMap线程不安全,
  2. ConcurrentHashMap、HashTable线程安全
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值