Map类集合与线程安全

本文深入探讨Java中Map集合的特性与应用,包括HashMap、Hashtable、TreeMap的区别及使用场景,以及Collections工具类的实用方法。同时,解析多线程环境下线程安全问题,并介绍如何确保线程安全,如使用synchronized关键字、ConcurrentHashMap等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Map
存储键值对形式的数据 key-value(K-V)
eg.Map<Integer,String>

  1. key是无序的,不可重复的–>set集合
  2. value无序的,可重复的 -->Collection集合
  3. 一个key只能对应一个value(如果想要value对应多个值可以存储在容器中list)
  4. 存储多个数据的时候,如果key相同,value会覆盖
    遍历:
  •  keySet()  返回所有的key
    
  •  values()  返回所有的值
    
  •  entrySet() Set<Map.Entry<K,V>
    

HashMap
底层:哈希表实现
缺点:线程不安全
存储的内容是键值对(key-value)映射

HashMap去重:根据key去重,自定义引用数据类型数据:hashCode()和equals()

Hashtable
基本和HashMap类似:线程安全

TreeMap
底层:红黑树结构
TreeMap去重:根据key去重,自定义引用数据类型数据:
内部和外部比较器
HashMap与TreeMap的区别:作规律排序就用TreeMap,否则用HashMap

Collections
可以操作容器类的工具类
方法列举:
void sort(List)//对容器元素按升序排序
void shuffle(List)//对容器元素进行随机排列
void reverse(List)//对容器元素进行逆序排列
void fill(List,Object)//用特定对象重写整个容器
int binarySearch(List,Object)//二分法寻找特定对象
处理HashMap的线程安全问题
1.使用Hashtable
2.Collections.synchronizedMap(Map)返回一个线程安全的map容器
3.juc包java.util.concurrent类 ConcurrentHashMap<K,V>//比较推荐使用此类

Properties
该类K-V键都是字符串形式数据
用于配置文件来调用:
(创建)src右键->new source folder->new file->db.properties->在内创建键值对形式的数据(eg.uname=scott)
创建对象:
Properties pro=new Properties();

通过IO流的形式加载:
pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(“db.properties”));
调取db内容:syso(pro.getProperty(“uname”));

多线程:
多个任务同时执行(只当需要多个任务同时执行时才需开启)
优点:资源利用率更好,简化有些程序设计,加快程序响应

进程:对与操作系统而言就是不同的任务执行,每一个进行都有自己的代码和数据空间,进程之间切换消耗比较大,一个进程中包含一到多个线程,是资源分配的最小单位
线程:一系列线程共享代码和数据空间,线程之间切换消耗较小,线程是cpu调度的最小单位

三高: 高可用(数据不会出错) 高性能(用户体验度好) 高并发(多用户同时操作抢购)
关注重点:
1.多线程的创建方式(3种)
1)继承Thread类 重写run()方法
2)实现Runnable接口,重写run()方法 --推荐
3)实现Callable接口,重写call()方法–了解 juc

2.保证线程安全问题 同步

3.线程状态

1)继承Thread类 重写run()方法
开启线程:Thread->start()开启线程(需要main中创建对象,利用Thread类的对象进行直接调用,eg.th.start())

2)实现Runnable接口,重写run()方法 --推荐
好处:避免带线程的局限性   实现资源共享
开启线程:使用Tread类中的start()方法开启 (静态代理)
调用方式比如:new Thread(类的对象).start();
应用例子:龟兔赛跑

3)实现callable接口,重写call方法
优点:可以抛出异常,可以存在返回值
缺点:使用复杂麻烦
步骤:创建指定线程池数量
eg.ExecutorService es=Executors.new FixedThreadPool(2);
创建了两个线程

线程的状态:
新生状态 : new,每个线程都有自己的运行空间
就绪状态 : start(),就绪不代表运行,代表线程具有可运行的能力,在就绪队列中排队等待cpu调度
运行状态 : cpu把时间片分配给某个线程,这个线程就就行运行状态
阻塞状态 : sleep()…
终止状态 : 执行完毕

注意:

  • 1)一个线程一旦进入到阻塞状态,阻塞解除无法直接回复运行状态,进入就绪状态等待cpu的调度
  • 2)一旦一个线程以终止,无法恢复,如果创建开启,也是新的线程

终止状态的几种情况:

  • 1)正常执行完毕
  • 2)强制结束 stop(),destroy(),方法已过时,不推荐使用
  • 3)通过标识进行控制–推荐

进入就绪状态的情况:

  • 1.start()
  • 2.阻塞状态结束
  • 3.yield()
  • 4.线程切换,被切换的线程进入到就绪状态

进入阻塞状态的情况:

  • 1.sleep()
  • 2.wait()
  • 3.join()
  • 4.IO操作

sleep使用:
1.加剧和查询方法发生问题的可能性
2.模拟网络延时

线程状态的检测
Thread.State以及 getState()

线程优先级: void setPriority(int newPriority)
更改线程的优先级。 提高先执行的概率,但不是绝对的
1~10 最小是1 最大是10 默认5
MAX_PRIORITY -->10
MIN_PRIORITY -->1
NORM_PRIORITY -->5
getPriority() 获取线程优先级别
eg. th.setPriority(Thread.Max_PRIORITY)
(th为Thread的对象)

线程安全问题:
多线程同时操作同一资源时可能出现的不安全问题(比如重复多次出现同一数值)

处理线程安全:
同步锁 synchronized
同步方法: 效率较低,简单
同步静态方法
同步成员方法
同步块: synchronized(this|类名.calss|资源(成员属性)){…}
锁this:锁住对象所有的成员属性,若只需锁一个资源,则直接锁资源。

锁资源,效率较高
资源变成自定义类型–>锁对对象的地址(不变)

注意:
1.锁一定要锁不变的内容 自定义类型对象地址
2.锁的范围太大,效率低,锁的范围太小锁不住

double check 双重检查 效率高,锁的范围小
锁静态方法,锁类的class对象都是锁类,锁住了这个类的所有对象

如懒汉单例模式的锁:

	public static SingleTon newInstance(){
  		    if(single==null){//检查①
  		    synchronized (SingleTon.class) {//检查②
				Thread.sleep(200);//此处为异常
				if(single==null){
					single=new SingleTon();
				}
			}  
			}
			return single;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值