当前位置:   article > 正文

java多线程学习(不安全的类)(一)_java线程不安全类

java线程不安全类

java多线程基础(不安全的类)

一、线程/进程、并发/并行

两者的概念:

进程:什么是进程呢?拿windows系统来说,比如qq.exe,微信等在运行的软件,就是一个独立的进程,可以打开任务管理器,查看一下自己电脑上的进程:

在这里插入图片描述

线程:线程是任务调度和执行的基本单位,一个进程可以包含多个线程。而线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
并发:在一个时间段,可能很短,多个线程可以去操作一个资源但不是真正意义上的同一时刻。
并行:在同一时间可以去操作不同的东西,就是做不同的事情。
并行需要电脑的多核支持,而并发不需要。

二、不安全的集合

首先引出线程的概念:以买票的程序

public class SaleTicketDemo01 {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        /**
         * 开始卖票,三个各自分配,跟cpu和操作系统有关,随机调度
         */
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        }, "C").start();
    }
}

/**
 * 资源类
 */
class Ticket{
    private int number = 30;
    /**
     * ReentrantLock: 可重入锁
     */
    Lock lock = new ReentrantLock();
    public void sale() {
        lock.lock();
        try {
            if (number > 0) {
                System.out.println(java.lang.Thread.currentThread().getName() +"\t 卖出第:" + (number--) + " \t 还剩下: " + number );
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

这里直接是使用 new Thread(); 来创建线程的,业务逻辑是。

存在30张票,分三个人进行售卖,那这个时候就有问题,会存在线程不安全的情况,比如:A不知道B卖了多少,就会存在数量不一致的情况,所以需要加上锁,这里采用的是java里面的可重入锁。就可以解决线程不安全的问题。

在java中有很多线程不安全的类,就说其中几个最常见的。

  1. ArrayList
	List<String> list = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行这段代码的时候会出现一个并发异常:java.util.ConcurrentModificationException,这就是因为线程不安全的原因造成的并发异常。

  • 可以选择 Vector来解决,但是这样会影响List的性能,所以不推荐使用该类处理。
List<String> list = new Vector<>();
  • 1
  • 选择Collections集合工具类来实现线程安全:
List<String> list = Collections.synchronizedList(new ArrayList<>());
  • 1
  • 选择写实集合类:CopyOnWriteArrayList;
List<String> list = new CopyOnWriteArrayList<>();
  • 1

这三种方式都可以解决List线程不安全的情况。

  1. HashSet
    同样身为集合,Set也存在线程不安全的情况。
	private static void setNotSafe() {
        Set<String> strings = new HashSet<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                strings.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(strings);
            }, String.valueOf(i)).start();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这段程序执行结果同样会报出异常:java.util.ConcurrentModificationException
解决方法也是和上面的List的一样,使用集合工具类和写实集合类。

  1. HashMap
    Map这个的解决办法有点不一样,当让集合工具类还是可以使用,然后还有就是使用:ConcurrentHashMap
private static void mapNotSafe() {
        Map<String, String> map = new ConcurrentHashMap<>(16);
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

三、总结

当然这只是很常见的一些,且实用率较高的一些类,还有StringBuilder、SimpleDateFormat等也是不安全的类,谢谢大家的阅读,线程、并发在java中算是基础也是一个难点,大家一起努力学习,五一学习快乐!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/670952
推荐阅读
相关标签
  

闽ICP备14008679号