线程不安全的类与写法

admin
2022-04-24 / 0 评论 / 169 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2022年04月24日,已超过733天没有更新,若内容或图片失效,请留言反馈。

线程不安全的类与写法

线程不安全的类:类的对象可以同时被多个线程访问,比如抛出异常,逻辑错误。下面介绍一些常见的类。

StringBuilder

StringBuilder线程不安全的类

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程不安全的类:StringBuilder
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:01
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoStringBuilder {
    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;
    //累加总和
    private static StringBuilder stringBuilder = new StringBuilder();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("字符长度Length=【{}】",stringBuilder.length());
    }

    /**
     * 累加
     */
    private  static void update(){
        stringBuilder.append(1);
    }

}

每次输出字符长度不一样,也不等于5000

StringBuffer

线程安全的类

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.ThreadSafety;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程安全的类:StringBuffer
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:06
 * @version: 1.0
 */
@Slf4j
@ThreadSafety
public class DemoStringBuffer {
    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;
    //累加总和
    private static StringBuffer stringBuffer = new StringBuffer();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("字符长度Length=【{}】", stringBuffer.length());
    }

    /**
     * 累加
     */
    private  static void update(){
        stringBuffer.append(1);
    }
}

输出结果:每次都是长度为5000.

StringBuffer为什么线程安全,看源码

    @Override
    @HotSpotIntrinsicCandidate
    public synchronized StringBuffer append(int i) {
        toStringCache = null;
        super.append(i);
        return this;
    }

因为StringBuffer所有的方法操作都加了synchronized。

区别

StringBuffer由于加了synchronized,性能上有损耗,没有StringBuilder性能高,在线程封闭中,堆栈封闭时,一般处理字符串局部变量时用StringBuilfer就行了。


SimpleDateFormat

线程不安全的类

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
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;

/**
 * @description: 线程不安全类: SimpleDateFormat
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:18
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoSimpleDateFormat {
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyyMMMdd");

    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
    }

    /**
     * 累加
     */
    private  static void update(){
        try {
            simpleDateFormat.parse("20220424");
        } catch (ParseException e) {
            log.error(e.getMessage());
        }
    }
}

输出结果:

    at java.base/java.lang.Double.parseDouble(Double.java:543)
    at java.base/java.text.DigitList.getDouble(DigitList.java:169)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-824" java.lang.NumberFormatException: For input string: "E.0220E0"
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
    at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.base/java.lang.Double.parseDouble(Double.java:543)
    at java.base/java.text.DigitList.getDouble(DigitList.java:169)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-717" java.lang.NumberFormatException: multiple points
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
    at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.base/java.lang.Double.parseDouble(Double.java:543)
    at java.base/java.text.DigitList.getDouble(DigitList.java:169)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-671" java.lang.NumberFormatException: For input string: ""
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.base/java.lang.Long.parseLong(Long.java:702)
    at java.base/java.lang.Long.parseLong(Long.java:817)
    at java.base/java.text.DigitList.getLong(DigitList.java:195)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-805" java.lang.NumberFormatException: multiple points
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1914)
    at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.base/java.lang.Double.parseDouble(Double.java:543)
    at java.base/java.text.DigitList.getDouble(DigitList.java:169)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-736" java.lang.NumberFormatException: For input string: ".20220424"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.base/java.lang.Long.parseLong(Long.java:678)
    at java.base/java.lang.Long.parseLong(Long.java:817)
    at java.base/java.text.DigitList.getLong(DigitList.java:195)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-740" java.lang.NumberFormatException: multiple points
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1914)
    at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.base/java.lang.Double.parseDouble(Double.java:543)
    at java.base/java.text.DigitList.getDouble(DigitList.java:169)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-695" java.lang.NumberFormatException: For input string: "E.0220"
    at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
    at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
    at java.base/java.lang.Double.parseDouble(Double.java:543)
    at java.base/java.text.DigitList.getDouble(DigitList.java:169)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2126)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "pool-1-thread-888" java.lang.NumberFormatException: For input string: "202204242022042420220424"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.base/java.lang.Long.parseLong(Long.java:692)
    at java.base/java.lang.Long.parseLong(Long.java:817)
    at java.base/java.text.DigitList.getLong(DigitList.java:195)
    at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121)
    at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)
    at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)
    at java.base/java.text.DateFormat.parse(DateFormat.java:393)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.update(DemoSimpleDateFormat.java:57)
    at com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormat.lambda$main$0(DemoSimpleDateFormat.java:40)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)

虽然SimpleDateFormat是线程不安全的类,但是可以通过线程封闭中,堆栈封闭(栈封闭)方法,将SimpleDateFormat定义到局部变量中,每次是一个新对象,这样来保证线程安全。

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.ThreadSafety;
import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程不安全类: SimpleDateFormat,通过堆栈封闭,实现线程安全。
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:18
 * @version: 1.0
 */
@Slf4j
@ThreadSafety
public class DemoSimpleDateFormatOk {
    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
    }

    /**
     * 通过线程封闭,将SimpleDateFormat定义在方法内,每次都是一个新的对象,来保证线程安全
     */
    private  static void update(){
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyyMMMdd");
            simpleDateFormat.parse("20220424");
        } catch (ParseException e) {
            log.error(e.getMessage());
        }
    }
}

输出结果:输出5000条,一样的。

09:27:17.633 [pool-1-thread-461] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424"
09:27:17.633 [pool-1-thread-460] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424"
09:27:17.634 [pool-1-thread-452] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424"
09:27:17.634 [pool-1-thread-445] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424"
09:27:17.634 [pool-1-thread-453] ERROR com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoSimpleDateFormatOk - Unparseable date: "20220424"
。。。。。

joda.time第三方包中DateTimeFormatter

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;


import com.yanxizhu.demo.concurrency.annotation.ThreadSafety;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程安全的类:Joda-time包里面的DateTimeFormatter需要单独导入
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:31
 * @version: 1.0
 */
@Slf4j
@ThreadSafety
public class DemoJodaTime {
    private static DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("yyyyMMdd");

    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(clientsTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(concurrencyTotal);

        for (int i = 0; i < clientsTotal; i++) {
            final int count = i;
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update(count);
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
    }

    /**
     * 通过线程安全对象dateTimeFormatter处理
     */
    private  static void update(int count){
        Date date = DateTime.parse("20220424", dateTimeFormatter).toDate();
        log.info("{},{}", count, date);
    }
}

输出结果:有5000条,线程安全的

09:45:06.164 [pool-1-thread-1947] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 1946,Sun Apr 24 00:00:00 CST 2022
09:45:06.154 [pool-1-thread-491] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 490,Sun Apr 24 00:00:00 CST 2022
09:45:06.184 [pool-1-thread-2943] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 2942,Sun Apr 24 00:00:00 CST 2022
09:45:06.169 [pool-1-thread-1911] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 1910,Sun Apr 24 00:00:00 CST 2022
09:45:06.169 [pool-1-thread-616] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 615,Sun Apr 24 00:00:00 CST 2022
09:45:06.168 [pool-1-thread-2551] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 2550,Sun Apr 24 00:00:00 CST 2022
09:45:06.144 [pool-1-thread-1415] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 1414,Sun Apr 24 00:00:00 CST 2022
09:45:06.154 [pool-1-thread-4611] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 4610,Sun Apr 24 00:00:00 CST 2022
09:45:06.169 [pool-1-thread-4760] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 4759,Sun Apr 24 00:00:00 CST 2022
09:45:06.167 [pool-1-thread-2388] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 2387,Sun Apr 24 00:00:00 CST 2022
09:45:06.184 [pool-1-thread-3990] INFO com.yanxizhu.demo.concurrency.threadUnSafetyClass.DemoJodaTime - 3989,Sun Apr 24 00:00:00 CST 2022
。。。。。

ArrayList

线程不安全的

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.joda.time.DateTime;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程不安全类:ArrayList
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:52
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoArrayList {
    private static List<Integer> list = new ArrayList<>();
    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            final int count = i;
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update(count);
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("list size:{}", list.size());
    }

    /**
     * 通过线程安全对象dateTimeFormatter处理
     */
    private  static void update(int count){
        list.add(count);
    }
}

输出结果:每次输出ist长度不同,线程不安全的。

HashSet

线程不安全类

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程不安全类:HashSet
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:52
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoHashSet {
    private static Set<Integer> set = new HashSet<>();
    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            final int count = i;
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update(count);
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("set size:{}", set.size());
    }

    /**
     * 通过线程安全对象dateTimeFormatter处理
     */
    private  static void update(int count){
        set.add(count);
    }
}

输出结果:每次长度不同,不是5000,线程不安全。

HashMap

线程不安全的

代码示例

package com.yanxizhu.demo.concurrency.threadUnSafetyClass;

import com.yanxizhu.demo.concurrency.annotation.UnThreadSafety;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * @description: 线程不安全类:HashMap
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/4/24 9:52
 * @version: 1.0
 */
@Slf4j
@UnThreadSafety
public class DemoHashMap {
    private static Map<Integer, Integer> map = new HashMap();
    //用户数量
    private static final int clientsTotal = 5000;
    //并发数量
    private static final int concurrencyTotal = 200;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //信号量
        final Semaphore semaphore = new Semaphore(concurrencyTotal);
        //闭锁
        final CountDownLatch countDownLatch = new CountDownLatch(clientsTotal);

        for (int i = 0; i < clientsTotal; i++) {
            final int count = i;
            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    update(count);
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("出现错误:【{}】", e.getMessage());
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("map size:{}", map.size());
    }

    /**
     * 通过线程安全对象dateTimeFormatter处理
     */
    private  static void update(int count){
        map.put(count, count);
    }
}

输出结果: 长度不是5000,每次长度不一样,线程不安全。

总结:线程安全类对应的不只一个。后面专门说明。

注意:先检查再执行这种类是线程不安全的,因为被分成2步了,if (condition(a)) { handle(1);}

2

评论 (0)

取消