并发包(笔记)

在JDK的并发包java.util.concurrent里提供了几个非常有用的并发容器和并发工具类。供我们在多线程开发中进行使用。这些集合和工具类都可以保证高并发的线程安全问题.

1.并发List集合_CopyOnWriteArrayList(重点)

List集合的特点:

​ 1.是一个有序的集合

​ 2.允许存储重复的元素

​ 3.包含一些带索引的方法

1).java.util.concurrent.CopyOnWriteArrayList(类):它是一个“线程安全”的ArrayList,我们之前学习的java.utils.ArrayList不是线程安全的。
2).如果是多个线程,并发访问同一个ArrayList,我们要使用:CopyOnWriteArrayList

需求:

1.创建一个被多个线程共享使用静态的ArrayList集合对象

2.使用Thread-0线程往集合中添加1000个元素

3.使用main线程往集合中添加1000个元素

4.统计集合的长度

CopyOnWriteArrayList集合底层采用了CAS机制乐观锁,可以保证多线程的安全,效率比Vector高

在这里插入图片描述

package com.itheima.demo11List;

import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;

/*
    需求:
        1.创建一个被多个线程共享使用静态的ArrayList集合对象
        2.使用Thread-0线程往集合中添加1000个元素
        3.使用main线程往集合中添加1000个元素
        4.统计集合的长度
 */
public class MyThread extends Thread {
    //1.创建一个被多个线程共享使用静态的ArrayList集合对象
    /*
        ArrayList集合:是一个多线程不安全的集合
     */
    //public static ArrayList<Integer> list = new ArrayList<>();

    /*
        java.util.Vector<E>:JDK1.0时期的集合,是最早期的单列集合
        与新 collection 实现不同,Vector 是同步的。
        Vector集合底层采用了synchronized悲观锁,可以保证多线程的安全,但是效率低下
     */
    //public static Vector<Integer> list = new Vector<>();

    /*
        java.util.concurrent.CopyOnWriteArrayList<E>集合 implements List<E>接口
        是JDK1.5之后出现的
        CopyOnWriteArrayList集合底层采用了CAS机制乐观锁,可以保证多线程的安全,效率比Vector高
     */
    public static CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();

    @Override
    public void run() {
        //2.使用Thread-0线程往集合中添加1000个元素
        System.out.println("Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!");
        for (int i = 0; i < 1000; i++) {
            list.add(i);//[0,1,2,3...999]
            //增加睡眠1毫秒的目的,提高线程安全问题出现的概率
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Thread-0线程,添加1000个元素完毕,执行线程任务结束了!");
    }
}
package com.itheima.demo11List;

public class Demo01List {
    public static void main(String[] args) throws InterruptedException {
        //创建MyThread对象,调用start方法,开启一个新的线程执行run方法
        MyThread mt = new MyThread();
        mt.start();

        //主线程在开启新的线程之后,会继续执行main方法中的代码
        //3.使用main线程往集合中添加1000个元素
        System.out.println("主线程开始往List集合中添加1000个元素!");
        for (int i = 0; i < 1000; i++) {
            MyThread.list.add(i);//[0,1,2,3...999]
            //增加睡眠1毫秒的目的,提高线程安全问题出现的概率
            Thread.sleep(1);
        }
        System.out.println("主线程添加1000个元素完毕,睡眠3秒钟,等待Thread-0线程执行完毕!");
        Thread.sleep(3000);
        System.out.println("两个线程都执行完毕,打印集合的长度:"+MyThread.list.size());
    }
}

ArrayList集合并发的问题:
1.存储的元素个数不对
2.会引发索引越界异常

主线程开始往List集合中添加1000个元素!
Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!
Thread-0线程,添加1000个元素完毕,执行线程任务结束了!
主线程添加1000个元素完毕,睡眠3秒钟,等待Thread-0线程执行完毕!
两个线程都执行完毕,打印集合的长度:1991
    
主线程开始往List集合中添加1000个元素!
Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 22
	at java.util.ArrayList.add(ArrayList.java:463)
	at com.itheima.demo11List.Demo01List.main(Demo01List.java:13)
Thread-0线程,添加1000个元素完毕,执行线程任务结束了!  

2.并发Set集合_CopyOnWriteArraySet(重点)
Set集合的特点:

​ 1.不允许存储重复元素

​ 2.不包含索引的方法

需求:

1.创建一个被多个线程共享使用静态的HashSet集合对象

2.使用Thread-0线程往集合中添加1000个元素

3.使用main线程往集合中添加1000个元素

4.统计集合的长度
在这里插入图片描述

package com.itheima.demo12Set;

import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArraySet;

/*
    需求:
        1.创建一个被多个线程共享使用静态的HashSet集合对象
        2.使用Thread-0线程往集合中添加1000个元素
        3.使用main线程往集合中添加1000个元素
        4.统计集合的长度
 */
public class MyThread extends Thread {
    //1.创建一个被多个线程共享使用静态的HashSet集合对象
    /*
        HashSet集合:是一个多线程不安全的集合
     */
    //public static HashSet<Integer> set = new HashSet<>();

    /*
        java.util.concurrent.CopyOnWriteArraySet<E>
        是JDK1.5之后出现的
        CopyOnWriteArraySet集合底层采用了CAS机制乐观锁,可以保证多线程的安全
     */
    public static CopyOnWriteArraySet<Integer> set = new CopyOnWriteArraySet<>();

    @Override
    public void run() {
        //2.使用Thread-0线程往集合中添加1000个元素
        System.out.println("Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!");
        for (int i = 0; i < 1000; i++) {
            set.add(i);//[0,1,2,3...999]
            //增加睡眠1毫秒的目的,提高线程安全问题出现的概率
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Thread-0线程,添加1000个元素完毕,执行线程任务结束了!");
    }
}
package com.itheima.demo12Set;

public class Demo01Set {
    public static void main(String[] args) throws InterruptedException {
        //创建MyThread对象,调用start方法,开启一个新的线程执行run方法
        MyThread mt = new MyThread();
        mt.start();

        //主线程在开启新的线程之后,会继续执行main方法中的代码
        //3.使用main线程往集合中添加1000个元素
        System.out.println("主线程开始往List集合中添加1000个元素!");
        for (int i = 1000; i < 2000; i++) {
            MyThread.set.add(i);//[1000,1001,1002,1003...1999]
            //增加睡眠1毫秒的目的,提高线程安全问题出现的概率
            Thread.sleep(1);
        }
        System.out.println("主线程添加1000个元素完毕,睡眠3秒钟,等待Thread-0线程执行完毕!");
        Thread.sleep(3000);
        System.out.println("两个线程都执行完毕,打印集合的长度:"+ MyThread.set.size());
    }
}

HashSet集合存在并发问题

主线程开始往List集合中添加1000个元素!
Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!
Thread-0线程,添加1000个元素完毕,执行线程任务结束了!
主线程添加1000个元素完毕,睡眠3秒钟,等待Thread-0线程执行完毕!
两个线程都执行完毕,打印集合的长度:1988

3.并发Map集合_ConcurrentHashMap(重点)
需求:

1.创建一个被多个线程共享使用静态的HashMap集合对象

2.使用Thread-0线程往集合中添加1000个元素

3.使用main线程往集合中添加1000个元素

4.统计集合的长度

package com.itheima.demo13Map;


import java.util.HashMap;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;

/*
    需求:
        1.创建一个被多个线程共享使用静态的HashMap集合对象
        2.使用Thread-0线程往集合中添加1000个元素
        3.使用main线程往集合中添加1000个元素
        4.统计集合的长度
 */
public class MyThread extends Thread {
    //1.创建一个被多个线程共享使用静态的HashMap集合对象
    /*
        HashMap集合:是一个多线程不安全的集合
     */
    //public static HashMap<Integer,Integer> map = new HashMap<>();

    /*
        java.util.Hashtable<K,V>:JDK1.0时期的集合,是最早期的双列集合
        不像新的 collection 实现,Hashtable 是同步的
        Hashtable集合底层采用了synchronized悲观锁,可以保证多线程的安全,但是效率低下
     */
    //public static Hashtable<Integer,Integer> map = new Hashtable<>();

    /*
        java.util.concurrent.ConcurrentHashMap<K,V><E>集合
        是JDK1.5之后出现的
        ConcurrentHashMap集合底层采用了CAS机制乐观锁,可以保证多线程的安全,效率比Hashtable高
     */
    public static ConcurrentHashMap<Integer,Integer> map = new ConcurrentHashMap<>();

    @Override
    public void run() {
        //2.使用Thread-0线程往集合中添加1000个元素
        System.out.println("Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!");
        for (int i = 0; i < 1000; i++) {
            map.put(i,i);//[0-0,1-1,2-2,3-3...999-999]
            //增加睡眠1毫秒的目的,提高线程安全问题出现的概率
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Thread-0线程,添加1000个元素完毕,执行线程任务结束了!");
    }
}
package com.itheima.demo13Map;

public class Demo01Map {
    public static void main(String[] args) throws InterruptedException {
        //创建MyThread对象,调用start方法,开启一个新的线程执行run方法
        MyThread mt = new MyThread();
        mt.start();

        //主线程在开启新的线程之后,会继续执行main方法中的代码
        //3.使用main线程往集合中添加1000个元素
        System.out.println("主线程开始往集合中添加1000个元素!");
        for (int i = 1000; i < 2000; i++) {
            MyThread.map.put(i,i);//[1000-1000,1001-1001...1999-1999]
            //增加睡眠1毫秒的目的,提高线程安全问题出现的概率
            Thread.sleep(1);
        }
        System.out.println("主线程添加1000个元素完毕,睡眠3秒钟,等待Thread-0线程执行完毕!");
        Thread.sleep(3000);
        System.out.println("两个线程都执行完毕,打印集合的长度:"+ MyThread.map.size());
        System.out.println(MyThread.map);
    }
}

HashMap集合存在并发问题:

主线程开始往集合中添加1000个元素!
Thread-0线程,执行线程任务了,开始往集合中添加1000个元素!
Thread-0线程,添加1000个元素完毕,执行线程任务结束了!
主线程添加1000个元素完毕,睡眠3秒钟,等待Thread-0线程执行完毕!
两个线程都执行完毕,打印集合的长度:1997

4.比较ConcurrentHashMap和Hashtable的效率

Java类库中,从1.0版本也提供一个线程安全的Map:Hashtable
Hashtable和ConcurrentHashMap有什么区别:
Hashtable采用的synchronized——悲观锁,效率更低。
ConcurrentHashMap:采用的CAS 机制——乐观锁,效率更高。

需求:

1.创建一个被多个线程共享使用静态的Hashtable集合(ConcurrentHashMap集合)对象

2.开启1000个线程,每个线程往集合中存储100000个数据

package com.itheima.demo14Map;

import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;

/*
    比较ConcurrentHashMap和Hashtable的效率
    Hashtable和ConcurrentHashMap有什么区别:
    Hashtable采用的synchronized——悲观锁,效率更低。
    ConcurrentHashMap:采用的CAS 机制——乐观锁,效率更高。
 */
public class MyThread extends Thread{
    //创建一个被多个线程共享使用静态的Hashtable集合(ConcurrentHashMap集合)对象
    //public static Hashtable<Integer,Integer> map = new Hashtable<>();
    public static ConcurrentHashMap<Integer,Integer> map = new ConcurrentHashMap<>();

    @Override
    public void run() {
        //每个线程往集合中存储100000个数据
        long s = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            map.put(i,i);
        }
        long e = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName()+"线程往集合中添加10万个数据耗时:"+(e-s)+"毫秒!");
    }
}
package com.itheima.demo14Map;

public class Demo01 {
    public static void main(String[] args) {
        //开启1000个线程,每个线程往集合中存储100000个数据
        for (int i = 0; i < 1000; i++) {
            new MyThread().start();
        }
    }
}

Hashtable效率低下原因:

public synchronized V put(K key, V value) 
public synchronized V get(Object key)

Hashtable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下Hashtable的效率非常低下。因为当一个线程访问Hashtable的同步方法,其他线程也访问Hashtable的同步方法时,会进入阻塞状态。如线程1使用put进行元素添加,线程2不但不能使用put方法添加元素,也不能使用get方法来获取元素,所以竞争越激烈效率越低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旭子在努力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值