HashMap&线程
1、HashMap概念
HashMap是一个散列表,存储内容是键值对(key-value)的映射,
HashMap继承了AbstractMap,实现了Map、Cloneable、java.io.Serializable的接口
HashMap的实现不是同步的,线程是不安全的,他的Key 、value都可以为null,此外HashMap中的映射不是有序的。
HashMap实例有两个参数影响其性能,分别是 初始容量、加载因子。加载因子就是哈希表在其容量自动创建之前可以达到多满的一种尺度,注意,当哈希表中的条目容量超出当前加载因子和容量的乘积之后,哈希表进行rehash操作,(重建内部的数据结构)
HashMap的构造函数:
// 默认构造函数。
HashMap()
// 指定“容量大小”的构造函数
HashMap(int capacity)
// 指定“容量大小”和“加载因子”的构造函数
HashMap(int capacity, float loadFactor)
// 包含“子Map”的构造函数
HashMap(Map<? extends K, ? extends V> map)
HashMap是通过“拉链法”实现的哈希表,包括几个重要的成员变量,table、size、threshold、loadfactor、modCount、
table是一个Entry[]数组类型,而 entry就是一个单向链表。键值对就存储在Entry数组中。
threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。
HashMap主要对外接口,clear() 清空整个HashMap 他是将所有的元素设置成NULL实现的。
1 public void clear() { 2 modCount++; 3 Entry[] tab = table; 4 for (int i = 0; i < tab.length; i++) 5 tab[i] = null; 6 size = 0; 7 }
HashMap中的方法containsKey()判断是否含有Key,containsKey()首先通过getEntry()获取key对应的Entry,然后判断Entry是否是NULL
HashMap中的方法containsValue()判断HashMap是否含有值为value 的元素。
HashMap中的方法entrySet()方法的作用是返回一个HashMap中所用的Entry的集合,他是一个集合
HashMap中的方法get()方法获取key对应的value
HashMap中的发方法put()方法作用是提供对外的接口,让HashMap对象可以通过put()将键值对添加到HashMap中
源代码:
public V put(K key, V value) { 2 // 若“key为null”,则将该键值对添加到table[0]中。 3 if (key == null) 4 return putForNullKey(value); 5 // 若“key不为null”,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。 6 int hash = hash(key.hashCode()); 7 int i = indexFor(hash, table.length); 8 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 9 Object k; 10 // 若“该key”对应的键值对已经存在,则用新的value取代旧的value。然后退出! 11 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 12 V oldValue = e.value; 13 e.value = value; 14 e.recordAccess(this); 15 return oldValue; 16 } 17 } 18 19 // 若“该key”对应的键值对不存在,则将“key-value”添加到table中 20 modCount++; 21 addEntry(hash, key, value, i); 22 return null; 23 }
HashMap的遍历方式,根据entrySet()获取HashMap的键值对的Set集合,再通过Iterator迭代器遍历得到的集合,
// 假设map是HashMap对象 // map中的key是String类型,value是Integer类型
Integer integ = null; Iterator iter = map.entrySet().iterator();
while(iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); // 获取key key = (String)entry.getKey(); // 获取value integ = (Integer)entry.getValue(); }
2、线程问题
(〃'▽'〃)------object类中的wait()方法导致当前的线程等待,直到其他线程调用notify()方法或者notifyAll()唤醒。
Thread.yield()方法----->线程让步,暂停当前正在执行的线程对象,把机会让给相同或者跟高优先级的线程。
join()----->线程加入,等待其他线程终止,在当前线程中调用另一个贤臣的join() 方法,则当前线程转入阻塞状态,直到另一个线程运行结束,当前线程再由阻塞状态转为就绪状态。
sleep和yield的区别:
sleep方法是当前线程进入停止状态,所以执行sleep()的线程在指定的时间内不会被执行,yield()只是使得当前线程重新回到可执行状态,所以调用yield()方法的线程可能会进入到执行状态后马上又被执行。
(〃'▽'〃)---- wait()和notify()方法含义:obj.wait()与obj.ootify()必须要与synchronize一起使用,wait和notify是针对已近获取了obj锁进行的操作,从语法角度上说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内
,从功能上说wait就是说线程获取对象锁之后,主动释放对象锁,同时 本线程休眠,直到其他的线程调用对象的notify方法唤醒线程,才能继续获得对象锁,并继续执行。notify()调用后并不是马上释放对象锁,二是在响应的synchronize{}语句块执行完之后,自动释放锁。主要就是wait()方法释放CPU的同时,释放了对象锁的控制。
如下:是一个使用锁机制结合HashMap
public class CallThread2 {
static int index = 0;
static int max = 4 * 2;
static HashMap<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
static {
for (int i = 0; i < 4; i++) {
map.put(i, new ArrayList<Integer>());
}
}
static boolean isRunning = true; //声明一个标志初始化为真
public static class MyRunnable implements Runnable {
int name;
Lock lock;
Condition condition;
private MyRunnable(int name, Lock lock, Condition condition) {
super();
this.name = name;
this.lock = lock;
this.condition = condition;
}
public boolean isMyName(int index) {
while (index != name) {
myWait();
if(!isRunning)return false;
return true;
}
return false;
}
public void myWait() {
lock.lock(); //获得锁
try {
condition.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
}
public void myNotifyAll() {
lock.lock();
condition.signalAll();
lock.unlock();
}
@Override
public void run() {
// TODO Auto-generated method stub
while (isRunning) {
while (isMyName(index % 4)) {
}
if(!isRunning)return;
for (int i = 0, arrIndex = index; i < 4; i++) {
try {
if (arrIndex-- < 0) {
break;
}
List<Integer> list = map.get(i);
if (list.size() < max) {
list.add(name + 1);
}
} catch (Exception e) {
}
}
System.err.println("A:" + map.get(0));
System.err.println("B:" + map.get(1));
System.err.println("C:" + map.get(2));
System.err.println("D:" + map.get(3));
System.err.println("-----------------------");
if (map.get(map.size() - 1).size() == max) {
isRunning = false;
myNotifyAll();
return;
} else {
index++;
}
myNotifyAll();
}
垂緌饮清露,流响出疏桐。
居高声自远,非是藉秋风。