现在下面这段代码:再一个集合中使用多线程进行同时读和写操作。
public class ThreadDemo4 {
public static void main(String[] args) {
//创建ArrayList集合
List<String> list=new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
//向集合中添加内容
list.add(UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
发现该程序运行起来之后,会报出错误,原因是同时对一个集合进行读写操作,那么可能出现的一种情况就是当还没有给集合里面添加内容的时候,线程就已经去读取了,这时候他是读不到的,所以就会出现异常。add()方法是没有使用锁syn关键字所以线程是不安全的
把List list=new ArrayList<>();替换为List list=new Vector<>();
可以去看Vector源码:
该类中的add方法是使用了synchronized关键字,所以线程是安全的
注:该方案使用的情况不多,它的版本是在jdk1.0
List<String> list=new Vector<>();
for (int i = 0; i < 130; i++) {
new Thread(()->{
//向集合中添加内容
list.add(UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(list);
},String.valueOf(i)).start();
}
使用List list= Collections.synchronizedList(new ArrayList<>());
//创建ArrayList集合
List<String> list= Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 130; i++) {
new Thread(()->{
//向集合中添加内容
list.add(UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(list);
},String.valueOf(i)).start();
}
List list=new CopyOnWriteArrayList<>();
//创建ArrayList集合
List<String> list=new CopyOnWriteArrayList<>();
for (int i = 0; i < 130; i++) {
new Thread(()->{
//向集合中添加内容
list.add(UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(list);
},String.valueOf(i)).start();
}
例如上图:
有一个集合(方框),有多个线程同时读取其中的数据,也就是并发读。当往集合中写入数据的时候,会把之前的集合复制一份出来,并在新的集合中进行独立的写。当写完之后会进行合并,再进行读的时候就会读取新的集合。中的数据。根据该过程可以解决集合并发出现的问题。就不会出现并发修改的异常
Set<String> set=new HashSet<>();
for (int i = 0; i < 130; i++) {
new Thread(()->{
//向集合中添加内容
set.add(UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(set);
},String.valueOf(i)).start();
}
Set set=new CopyOnWriteArraySet<>();
使用Set set=new CopyOnWriteArraySet<>();进行定义
普通定义HashMap
Map<String,String> map=new HashMap<>();
for (int i = 0; i < 130; i++) {
String key=String.valueOf(i);
new Thread(()->{
//向集合中添加内容
map.put(key,UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(map);
},String.valueOf(i)).start();
}
同样会出现刚刚的问题,那么在定义的时候使用ConcurrentHashMap进行定义
Map<String,String> map=new ConcurrentHashMap<>();
for (int i = 0; i < 130; i++) {
String key=String.valueOf(i);
new Thread(()->{
//向集合中添加内容
map.put(key,UUID.randomUUID().toString().substring(0,8));
//从集合中获取内容
System.out.println(map);
},String.valueOf(i)).start();
}
在并发编程中,Java提供了一些线程安全的集合类,如JUC集合和ConcurrentHashMap。这些集合类在多线程环境下能够保证数据的一致性和线程安全性。以下是对JUC集合和ConcurrentHashMap的总结:
JUC集合:JUC(Java.util.concurrent)集合是Java并发包中提供的线程安全的集合类。它们是对传统集合类的并发安全版本的改进。JUC集合包括了ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentSkipListSet等。它们采用了一些高效的并发算法和锁机制,能够在多线程环境下保证数据的一致性和线程安全性。
ConcurrentHashMap:ConcurrentHashMap是JUC集合中最常用的线程安全的Map实现。它通过将整个Map分成多个Segment(段)来实现并发访问的能力。每个Segment都相当于一个小的HashMap,只锁定当前访问的Segment,而不是整个Map,从而提高了并发性能。ConcurrentHashMap在读取操作上几乎没有任何锁开销,只有在写入操作时才需要进行同步。
线程安全性:JUC集合和ConcurrentHashMap的线程安全性是通过使用并发控制机制来实现的,如锁机制、CAS(Compare and Swap)操作、分段锁等。这些机制能够确保在多线程环境下,对集合的并发访问不会导致数据的不一致性或线程冲突。
性能优化:JUC集合和ConcurrentHashMap在设计上注重了性能的优化。它们采用了一些高效的并发算法和数据结构,如分段锁、无锁算法等,以提高并发访问的效率。同时,它们还提供了一些高级功能,如原子操作、并发迭代器等,以满足多线程环境下的特殊需求。
综上所述,JUC集合和ConcurrentHashMap是Java中用于实现线程安全的集合类。它们通过使用并发控制机制和高效的并发算法,能够在多线程环境下保证数据的一致性和线程安全性,并且具有较高的并发性能和灵活性。在并发编程中,使用这些线程安全的集合类能够有效地简化并发控制的复杂性,提高程序的稳定性和可靠性。
JUC集合和ConcurrentHashMap是Java中用于实现线程安全的集合类。它们具有以下特点和优势:
线程安全性:JUC集合和ConcurrentHashMap通过使用并发控制机制和锁机制,能够保证在多线程环境下对集合的并发访问不会导致数据的不一致性或线程冲突。
高效性能:JUC集合和ConcurrentHashMap在设计上注重了性能的优化。它们采用了一些高效的并发算法和数据结构,如分段锁、无锁算法等,以提高并发访问的效率。同时,它们还提供了一些高级功能,如原子操作、并发迭代器等,以满足多线程环境下的特殊需求。
并发性能优化:ConcurrentHashMap通过将整个Map分成多个Segment(段),只锁定当前访问的Segment,而不是整个Map,从而提高了并发性能。这种分段锁的设计使得读操作几乎没有任何锁开销,只有在写入操作时才需要进行同步。
灵活性和可扩展性:JUC集合和ConcurrentHashMap提供了一些高级功能,如原子操作、并发迭代器等,以满足多线程环境下的特殊需求。同时,它们还支持动态扩容和自动调整容量,能够根据实际需求进行灵活的扩展和调整。
并发编程简化:使用JUC集合和ConcurrentHashMap能够有效地简化并发控制的复杂性。它们提供了一些高级的并发控制机制,如原子操作、并发迭代器等,能够简化并发编程的代码逻辑,提高程序的稳定性和可靠性。
综上所述,JUC集合和ConcurrentHashMap是Java中用于实现线程安全的集合类,它们具有线程安全性、高效性能、并发性能优化、灵活性和可扩展性等优势。在并发编程中,使用这些线程安全的集合类能够有效地简化并发控制的复杂性,提高程序的稳定性和可靠性。