广告
返回顶部
首页 > 资讯 > 精选 >Java线程中的安全策略实例分析
  • 768
分享到

Java线程中的安全策略实例分析

2023-06-30 14:06:04 768人浏览 独家记忆
摘要

这篇文章主要介绍“Java线程中的安全策略实例分析”,在日常操作中,相信很多人在Java线程中的安全策略实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java线程中的安全策略实例分析”的疑惑有所帮助!

这篇文章主要介绍“Java线程中的安全策略实例分析”,在日常操作中,相信很多人在Java线程中的安全策略实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java线程中的安全策略实例分析”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    一、不可变对象

    不可变对象需要满足的条件

    (1)对象创建以后其状态就不能修改

    (2)对象所有域都是final类型

    (3)对象是正确创建的(在对象创建期间,this引用没有溢出)

    对于不可变对象,可以参见jdk中的String类

    final关键字:类、方法、变量

    (1)修饰类:该类不能被继承,String类,基础类型的包装类(比如Integer、Long等)都是final类型。final类中的成员变量可以根据需要设置为final类型,但是final类中的所有成员方法,都会被隐式的指定为final方法。

    (2)修饰方法:定方法不被继承类修改;效率。注意:一个类的private方法会被隐式的指定为final方法

    (3)修饰变量:基本数据类型变量(数值被初始化后不能再修改)、引用类型变量(初始化之后则不能再指向其他的对象)

    在JDK中提供了一个Collections类,这个类中提供了很多以unmodifiable开头的方法,如下:

    Collections.unmodifiableXXX: Collection、List、Set、Map…

    其中Collections.unmodifiableXXX方法中的XXX可以是Collection、List、Set、Map…

    此时,将我们自己创建的Collection、List、Set、Map,传递到Collections.unmodifiableXXX方法中,就变为不可变的了。此时,如果修改Collection、List、Set、Map中的元素就会抛出java.lang.UnsupportedOperationException异常。

    Google的Guava中,包含了很多以Immutable开头的类,如下:

    ImmutableXXX,XXX可以是Collection、List、Set、Map…

    注意:使用Google的Guava,需要在Maven中添加如下依赖包:

    <dependency>    <groupId>com.google.guava</groupId>    <artifactId>guava</artifactId>    <version>23.0</version></dependency>

    二、线程封闭

    (1)Ad-hoc线程封闭:程序控制实现,最糟糕,忽略

    (2)堆栈封闭:局部变量,无并发问题

    (3)ThreadLocal线程封闭:特别好的封闭方法

    三、线程不安全类与写法

    1. StringBuilder -> StringBuffer

    StringBuilder:线程不安全;

    StringBuffer:线程不安全;

    字符串拼接涉及到多线程操作时,使用StringBuffer实现

    在一个具体的方法中,定义一个字符串拼接对象,此时可以使用StringBuilder实现。因为在一个方法内部定义局部变量进行使用时,属于堆栈封闭,只有一个线程会使用变量,不涉及多线程对变量的操作,使用StringBuilder即可。

    2. SimpleDateFormat -> JodaTime

    SimpleDateFORMat:线程不安全,可以将其对象的实例化放入到具体的时间格式化方法中,实现线程安全
    JodaTime:线程安全

    SimpleDateFormat线程不安全的代码示例如下:

    package io.binghe.concurrency.example.commonunsafe;import lombok.extern.slf4j.Slf4j;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;@Slf4jpublic class DateFormatExample {    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");    //请求总数    public static int clientTotal = 5000;    //同时并发执行的线程数    public static int threadTotal = 200;    public static void main(String[] args) throws InterruptedException {        ExecutorService executorService = Executors.newCachedThreadPool();        final Semaphore semaphore = new Semaphore(threadTotal);        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);        for(int i = 0; i < clientTotal; i++){            executorService.execute(() -> {                try{                    semaphore.acquire();                    update();                    semaphore.release();                }catch (Exception e){                    log.error("exception", e);                }                countDownLatch.countDown();            });        }        countDownLatch.await();        executorService.shutdown();    }    public static void update(){        try {            simpleDateFormat.parse("20191024");        } catch (ParseException e) {            log.error("parse exception", e);        }    }}

    修改成如下代码即可。

    package io.binghe.concurrency.example.commonunsafe;import lombok.extern.slf4j.Slf4j;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;@Slf4jpublic class DateFormatExample2 {    //请求总数    public static int clientTotal = 5000;    //同时并发执行的线程数    public static int threadTotal = 200;    public static void main(String[] args) throws InterruptedException {        ExecutorService executorService = Executors.newCachedThreadPool();        final Semaphore semaphore = new Semaphore(threadTotal);        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);        for(int i = 0; i < clientTotal; i++){            executorService.execute(() -> {                try{                    semaphore.acquire();                    update();                    semaphore.release();                }catch (Exception e){                    log.error("exception", e);                }                countDownLatch.countDown();            });        }        countDownLatch.await();        executorService.shutdown();    }    public static void update(){        try {            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");            simpleDateFormat.parse("20191024");        } catch (ParseException e) {            log.error("parse exception", e);        }    }}

    对于JodaTime需要在Maven中添加如下依赖包:

    <dependency>    <groupId>joda-time</groupId>    <artifactId>joda-time</artifactId>    <version>2.9</version></dependency>

    示例代码如下:

    package io.binghe.concurrency.example.commonunsafe;import lombok.extern.slf4j.Slf4j;import org.joda.time.DateTime;import org.joda.time.format.DateTimeFormat;import org.joda.time.format.DateTimeFormatter;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;@Slf4jpublic class DateFormatExample3 {    //请求总数    public static int clientTotal = 5000;    //同时并发执行的线程数    public static int threadTotal = 200;    private static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd");    public static void main(String[] args) throws InterruptedException {        ExecutorService executorService = Executors.newCachedThreadPool();        final Semaphore semaphore = new Semaphore(threadTotal);        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);        for(int i = 0; i < clientTotal; i++){            final int count = i;            executorService.execute(() -> {                try{                    semaphore.acquire();                    update(count);                    semaphore.release();                }catch (Exception e){                    log.error("exception", e);                }                countDownLatch.countDown();            });        }        countDownLatch.await();        executorService.shutdown();    }    public static void update(int i){        log.info("{} - {}", i, DateTime.parse("20191024", dateTimeFormatter));    }}

    3. ArrayList、HashSet、HashMap等Collections集合类为线程不安全类

    4. 先检查再执行:if(condition(a)){handle(a);}

    注意:这种写法是线程不安全的!!!!!

    两个线程同时执行这种操作,同时对if条件进行判断,并且a变量是线程共享的,如果两个线程均满足if条件,则两个线程会同时执行handle(a)语句,此时,handle(a)语句就可能不是线程安全的。

    不安全的点在于两个操作中,即使前面的执行过程是线程安全的,后面的过程也是线程安全的,但是前后执行过程的间隙不是原子性的,因此,也会引发线程不安全的问题。

    实际过程中,遇到if(condition(a)){handle(a);}类的处理时,考虑a是否是线程共享的,如果是线程共享的,则需要在整个执行方法上加锁,或者保证if(condition(a)){handle(a);}的前后两个操作(if判断和代码执行)是原子性的。

    四、线程安全-同步容器

    1. ArrayList -> Vector, Stack

    ArrayList:线程不安全;

    Vector:同步操作,但是可能会出现线程不安全的情况,线程不安全的代码示例如下:

    public class VectorExample {    private static Vector<Integer> vector = new Vector<>();    public static void main(String[] args) throws InterruptedException {        while (true){            for(int i = 0; i < 10; i++){                vector.add(i);            }            Thread thread1 = new Thread(new Runnable() {                @Override                public void run() {                    for(int i = 0; i < vector.size(); i++){                        vector.remove(i);                    }                }            });            Thread thread2 = new Thread(new Runnable() {                @Override                public void run() {                    for(int i = 0; i < vector.size(); i++){                        vector.get(i);                    }                }            });            thread1.start();            thread2.start();        }    }}

    Stack:继承自Vector,先进后出。

    2. HashMap -> HashTable(Key, Value都不能为null)

    HashMap:线程不安全;

    HashTable:线程安全,注意使用HashTable时,Key, Value都不能为null;

    3. Collections.synchronizedXXX(List、Set、Map)

    注意:在遍历集合的时候,不要对集合进行更新操作。当需要对集合中的元素进行删除操作时,可以遍历集合,先对需要删除的元素进行标记,集合遍历结束后,再进行删除操作。例如,下面的示例代码:

    public class VectorExample3 {    //此方法抛出:java.util.ConcurrentModificationException    private static void test1(Vector<Integer> v1){        for(Integer i : v1){            if(i == 3){                v1.remove(i);            }        }    }    //此方法抛出:java.util.ConcurrentModificationException    private static void test2(Vector<Integer> v1){        Iterator<Integer> iterator = v1.iterator();        while (iterator.hasNext()){            Integer i = iterator.next();            if(i == 3){                v1.remove(i);            }        }    }    //正常    private static void test3(Vector<Integer> v1){        for(int i = 0; i < v1.size(); i++){            if(i == 3){                v1.remove(i);            }        }    }    public static void main(String[] args) throws InterruptedException {        Vector<Integer> vector = new Vector<>();        vector.add(1);        vector.add(2);        vector.add(3);        //test1(vector);        //test2(vector);        test3(vector);    }}

    五、线程安全-并发容器J.U.C

    J.U.C表示的是java.util.concurrent报名的缩写。

    1. ArrayList -> CopyOnWriteArrayList

    ArrayList:线程不安全;

    CopyOnWriteArrayList:线程安全;

    写操作时复制,当有新元素添加到CopyOnWriteArrayList数组时,先从原有的数组中拷贝一份出来,然后在新的数组中进行写操作,写完之后再将原来的数组指向到新的数组。整个操作都是在锁的保护下进行的。

    CopyOnWriteArrayList缺点:

    (1)每次写操作都需要复制一份,消耗内存,如果元素特别多,可能导致GC

    (2)不能用于实时读的场景,适合读多写少的场景;

    CopyOnWriteArrayList设计思想:

    (1)读写分离

    (2)最终一致性

    (3)使用时另外开辟空间,解决并发冲突

    注意:CopyOnWriteArrayList读操作时,都是在原数组上进行的,不需要加锁,写操作时复制,当有新元素添加到CopyOnWriteArrayList数组时,先从原有的集合中拷贝一份出来,然后在新的数组中进行写操作,写完之后再将原来的数组指向到新的数组。整个操作都是在锁的保护下进行的。

    2.HashSet、TreeSet -> CopyOnWriteArraySet、ConcurrentSkipListSet

    CopyOnWriteArraySet:线程安全的,底层实现使用了CopyOnWriteArrayList。

    ConcurrentSkipListSet:JDK6新增的类,支持排序。可以在构造时,自定义比较器,基于Map集合。在多线程环境下,ConcurrentSkipListSet中的contains()方法、add()、remove()、retain()等操作,都是线程安全的。但是,批量操作,比如:containsAll()、addAll()、removeAll()、retainAll()等操作,并不保证整体一定是原子操作,只能保证批量操作中的每次操作是原子性的,因为批量操作中是以循环的形式调用的单步操作,比如removeAll()操作下以循环的方式调用remove()操作。如下代码所示:

    //ConcurrentSkipListSet类型中的removeAll()方法的源码public boolean removeAll(Collection<?> c) {    // Override AbstractSet version to avoid unnecessary call to size()    boolean modified = false;    for (Object e : c)        if (remove(e))            modified = true;    return modified;}

    所以,在执行ConcurrentSkipListSet中的批量操作时,需要考虑加锁问题。

    注意:ConcurrentSkipListSet类不允许使用空元素(null)。

    3. HashMap、TreeMap -> ConcurrentHashMap、ConcurrentSkipListMap

    ConcurrentHashMap:线程安全,不允许空值

    ConcurrentSkipListMap:是TreeMap的线程安全版本,内部是使用SkipList跳表结构实现

    4.ConcurrentSkipListMap与ConcurrentHashMap对比如下

    (1)ConcurrentSkipListMap中的Key是有序的,ConcurrentHashMap中的Key是无序的;

    (2)ConcurrentSkipListMap支持更高的并发,对数据的存取时间和线程数几乎无关,也就是说,在数据量一定的情况下,并发的线程数越多,ConcurrentSkipListMap越能体现出它的优势。

    注意:在非对线程下尽量使用TreeMap,另外,对于并发数相对较低的并行程序,可以使用Collections.synchronizedSortedMap,将TreeMap进行包装;对于高并发程序,使用ConcurrentSkipListMap提供更高的并发度;在多线程高并发环境中,需要对Map的键值对进行排序,尽量使用ConcurrentSkipListMap。

    到此,关于“Java线程中的安全策略实例分析”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    --结束END--

    本文标题: Java线程中的安全策略实例分析

    本文链接: https://www.lsjlt.com/news/329610.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Java线程中的安全策略实例分析
      这篇文章主要介绍“Java线程中的安全策略实例分析”,在日常操作中,相信很多人在Java线程中的安全策略实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java线程中的安全策略实例分析”的疑惑有所帮助!...
      99+
      2023-06-30
    • Java线程安全与不安全实例分析
      本篇内容主要讲解“Java线程安全与不安全实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java线程安全与不安全实例分析”吧!当我们查看JDK API的时候,总会发现一些类说明写着,线程...
      99+
      2023-06-17
    • Java策略模式实例分析
      这篇文章主要讲解了“Java策略模式实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java策略模式实例分析”吧!优点算法可以自由切换。避免使用多重条件判断。扩展性良好。缺点策略类会增...
      99+
      2023-06-29
    • Html5中内容安全策略CSP的示例分析
      这篇文章主要为大家展示了“Html5中内容安全策略CSP的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Html5中内容安全策略CSP的示例分析”这篇文...
      99+
      2022-10-19
    • 一文详解Java线程中的安全策略
      目录一、不可变对象二、线程封闭三、线程不安全类与写法四、线程安全-同步容器1. ArrayList -> Vector, Stack2. HashMap -> HashT...
      99+
      2022-11-13
    • java中stringbuffer线程安全分析的示例
      这篇文章主要介绍java中stringbuffer线程安全分析的示例,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基于Java的实现了...
      99+
      2023-06-14
    • Java线程安全与同步实例分析
      本篇内容介绍了“Java线程安全与同步实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!线程安全问题多个线程可能会共享(访问)同一个资源...
      99+
      2023-06-30
    • Python线程安全实例分析
      这篇文章主要介绍“Python线程安全实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python线程安全实例分析”文章能帮助大家解决问题。一、什么是线程安全?线程安全,名字就非常直接,在多线...
      99+
      2023-06-29
    • Java多线程中线程安全问题的示例分析
      这篇文章主要介绍了Java多线程中线程安全问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1. 什么是线程安全和线程不安全?什么是线程安全呢?当多个线程并发访问某...
      99+
      2023-06-29
    • java中线程安全问题举例分析
      这篇文章主要讲解了“java中线程安全问题举例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java中线程安全问题举例分析”吧!一、什么时候数据在多线程并发的环境下会存在安全问题?三个条...
      99+
      2023-06-21
    • Java线程之安全与不安全的示例分析
      这篇文章将为大家详细讲解有关Java线程之安全与不安全的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。当我们查看JDK API的时候,总会发现一些类说明写着,线程安全或者线程不安全,比如说Stri...
      99+
      2023-05-30
      java
    • Java线程安全状态的示例分析
      这篇文章主要为大家展示了“Java线程安全状态的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java线程安全状态的示例分析”这篇文章吧。一、观察线程的所有状态线程的状态是一个枚举类型 ...
      99+
      2023-06-29
    • java策略模式的示例分析
      这篇文章给大家分享的是有关java策略模式的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。类型:行为类模式类图:  &...
      99+
      2023-05-30
      java
    • java中SimpleDateFormat非线程安全问题的示例分析
      小编给大家分享一下java中SimpleDateFormat非线程安全问题的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!SimpleDateFormat非线程安全问题实现1000个线程的时间格式化package&...
      99+
      2023-06-20
    • python线程安全的示例分析
      这篇文章给大家分享的是有关python线程安全的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。python可以做什么Python是一种编程语言,内置了许多有效的工具,Python几乎无所不能,该语言通俗易...
      99+
      2023-06-14
    • Java线程实例分析
      今天小编给大家分享一下Java线程实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。启动一个线程T1=new YourT...
      99+
      2023-06-03
    • Java设计模式之策略模式实例分析
      这篇文章主要介绍“Java设计模式之策略模式实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java设计模式之策略模式实例分析”文章能帮助大家解决问题。1.基本介绍1)策略模式(Strateg...
      99+
      2023-06-30
    • Redis中过期策略的示例分析
      小编给大家分享一下Redis中过期策略的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!概述设置过期时间expire key time(以秒为单位) 这是最...
      99+
      2023-06-15
    • java设计模式中策略模式的示例分析
      小编给大家分享一下java设计模式中策略模式的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!策略模式策略模式(Strategy Pattern)属于行为型模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实...
      99+
      2023-06-20
    • Python中线程安全队列Queue的示例分析
      小编给大家分享一下Python中线程安全队列Queue的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、什么是队列?像排队一样,从头到尾排成一排,还可以有人继续往后排队,这就是队列。这里学委想说的是Queue这个...
      99+
      2023-06-29
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作