哈希集线程安全吗? (详细的代码验证)

电脑杂谈  发布时间:2020-05-31 01:23:47  来源:网络整理

线程安全和线程非安全_线程通信问题_线程安全问题代码

什么是线程安全性?读写数据需要线程隔离,这不会导致数据丢失和不一致,并且每次修改数据都不应将其覆盖.

银行提款的经典示例. 帐户A最初为0,线程A读取0,然后保存100(数据尚未写入),线程B读取0,也保存100. 我们看到的是余额100. 这是不科学的,这是称为线程不安全. 因此,我们必须控制存取对象,让我们锁定数据操作的对象,并在其他线程可以实现线程安全之前更新数据.

线程安全和线程非安全_线程通信问题_线程安全问题代码

这一次我们证明HashSet,我们知道Set接口已实现. Set的特点是不会重复存储的数据. 因为它将首先读取内部保存的数据(如果存在),如果不存储它,否则将被存储. 换句话说,数据存储操作分为两个步骤,首先读取,然后写入. 假设它不是线程安全的,则可能发生的情况是线程安全问题代码,当线程A确定设置的对象不具有元素并将要插入该元素时,线程B也会确定该元素在其中不存在. 对象,也可以插入. 结果将插入两个相同的元素.

线程安全和线程非安全_线程通信问题_线程安全问题代码

我们设计了这样的演示:

class TestHashSet implements Runnable{
    // 实现Runnable 让该集合能被多个线程访问
    Set<Integer> set = new HashSet<Integer>();
    // 线程的执行就是插入5000个整数
    @Override
    public void run() {
        for (int i = 0;i < 5000;i ++) {
            set.add(i);
        }
    }
}

线程安全和线程非安全_线程安全问题代码_线程通信问题

我们在主线程上进行测试:

  TestHashSet run2 = new TestHashSet();
        // 实例化两个线程
        Thread t6 = new Thread(run2);
        Thread t7 = new Thread(run2);
        // 启动两个线程
        t6.start();
        t7.start();
        // 当前线程等待加入到调用线程后
        t6.join();
        t7.join();
        // 打印出集合的size
        System.out.println(run2.set.size());

线程通信问题_线程安全和线程非安全_线程安全问题代码

大多数打印结果是预期的5000,但偶尔会超过5000. 这导致了前面提到的情况线程安全问题代码,证明HashSet不是线程安全的类.

实际上,通过查看源代码,可以发现HashSet使用HashMap在内部维护数据. 根本原因是HashMap不是线程安全的类. 这导致HashSet的非线程安全. 有关Java集合的更多知识,请关注[PHP中文网: java视频]

最后,一个完整的代码案例验证:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 验证HashSet不是线程安全
 */
public class HashSetTest {
    public static void main(String[] args) {
        final Set<Integer> set = new HashSet<>();// 结果可能大于1000
//        final Set<Integer> set = Collections.synchronizedSet(new HashSet<>());// 结果等于1000
//        final Set<Integer> set = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());// 结果等于1000
        // 往set写入1-1000
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 1000; i++) {
                    set.add(i);
                }
            }
        };
        int threadNum = 10;// 线程数
        List<Thread> threadList = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            Thread thread = new Thread(runnable);
            threadList.add(thread);
            thread.start();
        }
        // 主线程等待子线程执行完成
        for (Thread thread : threadList) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(set.size());// 结果可能大于1000
    }
}

以上哈希集线程安全吗? (详细的代码验证)有关更多详细信息,请关注php中文网络上的其他相关文章!


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-228274-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...