Java中线程安全的集合

简介: Java中线程安全的集合

Java中线程安全的集合


引言:

         本文主要分享了Collection体系集合下除了Vector以外的线程安全集合,包括:Collection中的安全工具方法、子类CopyOnWriteArrayList、CopyOnWriteArraySet、ConcurrentHashMap、Queue接口、ConcurrentLinkedQueue、BlockingQueue以及阻塞队列;

相关文章:

  • Java多线程超详细笔记:分享了多线程的实现方式、7种状态、线程安全的两种解决方案以及死锁、生产者消费者问题;
  • Java高级多线程:分享了多线程中的线程池概念以及获取线程池的方法、Callable接口、Future接口、线程的同步以及异步、ReentrantLock(重入锁)、ReentrantRaedWriteLock(读写锁)

@[toc]
Collection体系集合下除了Vector以外的线程安全集合;(线程安全且没有影响效率)

Vector:对方法多加了把锁,性能低;

在这里插入图片描述

1. Collection中的工具方法

Collection工具类中提供了多个可以获得线程安全集合的方法;

  • public static < T >Collection< T > synchronizedCollection(Collection< T > c)
  • public static < T >List< T > synchronizedList(List< T > list)
  • public static < T >Set< T > synchronizedSet(Collection< T > set)
  • public static < K,V >Map< K,V > synchronizedMap(Collection< K,V > map)
  • public static < T >SortedSet< T > synchronizedSortedSet(Collection< T > s)
  • public static < K,V >SortedMap< K,V > synchronizedSortedMap(Collection< K,V > m)
  • JDK1.2提供,接口统一、维护性高,但性能没有提升,均以synchonized实现;
public class TestCollectionsForSyn {
   
   
    public static void main(String[] args) {
   
   
        List<String> list = new ArrayList<String>();

        List<String> safeList =  Collections.synchronizedList(list);//Collections$SynchronizedList
        //和普通集合应用无差别
        safeList.add("A");//SynchronizedList里的add方法。该方法有锁
        safeList.add("B");
        safeList.add("C");
        safeList.remove(1);
        safeList.get(1);

        Set<String> sets = new HashSet<String>();
        Set<String> newSet = Collections.synchronizedSet(sets);
        newSet.add("A");
        newSet.add("B");
        newSet.add("C");

        for(String s : newSet) {
   
   
            System.out.println(s);
        }
    }
}
  • 只是加入了Synchronized锁,使得集合安全

2. CopyOnWriteArrayList

  • ArrayList的一个线程安全的变体,与ArrayList的使用方式一样;

  • 写有锁,读无锁,读写之间不阻塞,优于读写锁;

  • 写入时,先copy一个容器副本、再添加新元素,最后替换引用;

public class TestCopyOnWriteArrayList {
   
   
    public static void main(String[] args) {
   
   
        CopyOnWriteArrayList<String> alist = new CopyOnWriteArrayList<String>();
        //写操作有锁
        alist.add("A");//将底层数组做一次复制,写的是新数组,完成赋值后将新替换为旧
        alist.add("B");//每调用一次,底层方法扩容一次
        //读操作无锁
        System.out.println(alist.get(1));//读是写操作完成之前的旧数组写完后才能读到值
    }
}

3. CopyOnWriteArraySet

  • 线程安全的Set,底层使用CopyOnWriteList实现;

  • 唯一不同在于使用addIfAbsent()添加元素,会遍历数组;

  • 如果存在元素,则不添加;

public class TestCopyOnWriteArraySet {
   
   
    public static void main(String[] args) {
   
       
        //无序、无下标、不允许重复
        CopyOnWriteArraySet<String> aset = new CopyOnWriteArraySet<String>();
        //写操作  表面使用的是add方法,底层实际是用的CopyOnWriteArrayList的 addIfAbsent()来判断要插入的新值是否存在
        aset.add("A"); 
        aset.add("B");
        aset.add("C");

        for(String s : aset) {
   
   
            System.out.println(s);
        }
    }
}

4. ConcurrentHashMap

  • 初始容量默认为16段(Segment),使用分段锁设计,用法与HashMap一样;

  • 不对整个Map加锁,而是为每个Segment加锁;

  • 当多个对象存入同一个Segment时,才需要互斥;

  • 最理想状态为16个对象分别存入16个Segment,并行数量16;

public class TestConcurrentHashMap {
   
   
    public static void main(String[] args) {
   
   
        HashMap<String,String> maps = new HashMap<String,String>();
        ConcurrentHashMap<String, String> ch = new ConcurrentHashMap<String, String>();

        ch.put("A","卡卡");
        ch.keySet();
    }
}
  • JDK1.7:分段锁设计Segment
  • JDK1.8:CAS交换算法和同步锁,同步锁锁的是表头对象,拿到锁的对象要先做节点遍历。查看有没有相同的key,相同覆盖,不同,则挂在最后一个节点的next上;

5. Queue接口(队列)

Collection的子接口,表示队列FIFO(First In First Out)

常用方法:

  • 抛出异常:

    boolean add(E e):顺序添加一个元素(达到上限后,在添加则会抛出异常)

    E remove():获得第一个元素并移除(如果队列没有元素时,抛出异常)

    E element():获得第一个元素但是不移除(如果队列没有元素时,抛出异常)

  • 返回特殊值(推):

    boolean offer(E e):顺序添加一个元素(达到上限后,在添加则会返回false)

    E poll():获得第一个元素并移除(如果队列没有元素时,返回null)

    E keep():获得第一个元素但是不移除(如果队列没有元素时,返回null)

5.1 ConcurrentLinkedQueue

线程安全、可高效的读写的队列,高并发下性能最好的队列

无锁、CAS比较算法,修改的方法包括三个核心参数

  • V:要更新的变量;
  • E:预期值;
  • N:新值

当V==E时,V=N;否则表示已经被更新过,取消当前操作;

public class TestQueue {
   
   
    public static void main(String[] args) {
   
   
        //线程安全
        Queue<String> q = new ConcurrentLinkedQueue<String>();

        q.offer("A");//插入
        q.offer("B");
        q.offer("C");

        q.poll();//删除表头
        System.out.println(q.peek());//获得表头

        System.out.println(link.peek());//队列中的第一个元素
    }
}

5.2 BlockingQueue接口

Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。

常用方法:

  • void put(E e)//将指定元素插入此队列中,如果没有可用空间则等待
  • E take():获取并移除此队列头部元素,如果没有可用元素则等待
  • 常用以解决生产者、消费者问题;

5.3 阻塞队列

ArrayBlockingQueue:数组结构实现,有界队列;(手工固定上限)

//手动固定队列上限
BlockingQueue<String> bq = new ArrayBlockingQueue<String>(3);

LinkedBlockingQueue:链表结构实现,无界队列;(默认上限Integer.MAX_VALUE)

//无界队列  最大有 Integer.MAX_VALUE
BlockingQueue<String> lbq = new LinkedBlockingQueue<String>();
目录
相关文章
|
1天前
|
Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第13天】在计算机科学中,多线程是一种使得程序可以同时执行多个任务的技术。在Java语言中,多线程的实现主要依赖于java.lang.Thread类和java.lang.Runnable接口。本文将深入探讨Java中的多线程编程,包括其基本概念、实现方法以及一些常见的问题和解决方案。
|
1天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第13天】 在Java开发中,并发编程是一个复杂且重要的领域。它不仅关系到程序的线程安全性,也直接影响到系统的性能表现。本文将探讨Java并发编程的核心概念,包括线程同步机制、锁优化技术以及如何平衡线程安全和性能。通过分析具体案例,我们将提供实用的编程技巧和最佳实践,帮助开发者在确保线程安全的同时,提升应用性能。
10 1
|
2天前
|
Java 调度
Java一分钟之线程池:ExecutorService与Future
【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。
17 5
|
2天前
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
3天前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
13 3
|
3天前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
55 2
|
3天前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
43 3
|
3天前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第11天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个方面,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。我们将通过实例和代码片段来说明这些概念和技术。
4 0
|
3天前
|
Java 调度
Java并发编程:深入理解线程池
【5月更文挑战第11天】本文将深入探讨Java中的线程池,包括其基本概念、工作原理以及如何使用。我们将通过实例来解释线程池的优点,如提高性能和资源利用率,以及如何避免常见的并发问题。我们还将讨论Java中线程池的实现,包括Executor框架和ThreadPoolExecutor类,并展示如何创建和管理线程池。最后,我们将讨论线程池的一些高级特性,如任务调度、线程优先级和异常处理。
|
2月前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【2月更文挑战第22天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个主题,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。
16 0