java测试并发类(java并发三大特性)

发布时间:2022-11-08

本文目录一览:

  1. 北大青鸟java培训:Java并发编程常用的类和集合?
  2. java并发包有哪些类
  3. JAVA并发编程实战怎么样
  4. java并发集合有哪些
  5. JAVA如何写一个纯并发的压力测试

北大青鸟java培训:Java并发编程常用的类和集合?

AtomicInteger 可以用原子方式更新 int 值。 AtomicBooleanAtomicIntegerAtomicLongAtomicReference 的实例各自提供对相应类型单个变量的访问和更新。 Java课程培训机构认为基本的原理都是使用 CAS 操作:boolean compareAndSet(expectedValue, updateValue); 如果此方法(在不同的类间参数类型也不同)当前保持 expectedValue,则以原子方式将变量设置为 updateValue,并在成功时返回 true

循环CAS

参考 AtomicInteger 中的实现:

public final int getAndIncrement() {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

ABA问题

因为 CAS 需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是 A,变成了 B,又变成了 A,那么使用 CAS 进行检查时会发现它的值没有发生变化,但是实际上却变化了。 ABA 问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么 A-B-A 就会变成 1A-2B-3A。 从 Java 1.5 开始 JDK 的 atomic 包里提供了一个类 AtomicStampedReference 来解决 ABA 问题。这个类的 compareAndSet 方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

ArrayBlockingQueue

一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部是在队列中存在时间最长的元素,队列的尾部是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。 这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。 此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。

LinkedBlockingQueue

一个基于已链接节点的、范围任意的阻塞队列。此队列按 FIFO(先进先出)排序元素。队列的头部是在队列中时间最长的元素,队列的尾部是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列获取操作会获得位于队列头部的元素。 链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。可选的容量范围构造方法参数作为防止队列过度扩展的一种方法。如果未指定容量,则它等于 Integer.MAX_VALUE。除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点。 如果构造一个 LinkedBlockingQueue 对象,而没有指定其容量大小,LinkedBlockingQueue 会默认一个类似无限大小的容量(Integer.MAX_VALUE),这样的话,如果生产者的速度一旦大于消费者的速度,也许还没有等到队列满阻塞产生,系统内存就有可能已被消耗殆尽了。

java并发包有哪些类

  1. CyclicBarrier 一个同步辅助类,允许一组线程相互等待,直到这组线程都到达某个公共屏障点。该 barrier 在释放等待线程后可以重用,因此称为循环的 barrier。 示例:
    package test;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class Recipes_CyclicBarrier {
        public static CyclicBarrier barrier = new CyclicBarrier(10);
        public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();
            for (int i = 1; i <= 10; i++) {
                executor.submit(new Thread(new Runner(i + "号选手")));
            }
            executor.shutdown();
        }
    }
    class Runner implements Runnable {
        private String name;
        public Runner(String name) {
            this.name = name;
        }
        @Override
        public void run() {
            System.out.println(name + "准备好了。");
            try {
                Recipes_CyclicBarrier.barrier.await();
            } catch (Exception e) {
            }
            System.out.println(name + "起跑!");
        }
    }
    
  2. CountDownLatch CountDownLatchCyclicBarrier 有点类似,但是还是有些区别的。CountDownLatch 也是一个同步辅助类,它允许一个或者多个线程一直等待,直到正在其他线程中执行的操作完成。它是等待正在其他线程中执行的操作,并不是线程之间相互等待。CountDownLatch 初始化时需要给定一个计数值,每个线程执行完之后,必须调用 countDown() 方法使计数值减 1,直到计数值为 0,此时等待的线程才会释放。 示例:
    package test;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class CountDownLatchDemo {
        public static CountDownLatch countDownLatch = new CountDownLatch(10);
        public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();
            for (int i = 1; i <= 10; i++) {
                executor.submit(new Thread(new Runner1(i + "号选手")));
            }
            executor.shutdown();
        }
    }
    class Runner1 implements Runnable {
        private String name;
        public Runner1(String name) {
            this.name = name;
        }
        @Override
        public void run() {
            System.out.println(name + "准备好了。");
            CountDownLatchDemo.countDownLatch.countDown();
            try {
                CountDownLatchDemo.countDownLatch.await();
            } catch (Exception e) {
            }
            System.out.println(name + "起跑!");
        }
    }
    
  3. CopyOnWriteArrayList CopyOnWriteArraySet CopyOnWriteArrayListCopyOnWriteArraySet 是并发容器,适合读多写少的场景,如网站的黑白名单设置。缺点是内存占用大,数据一致性的问题,CopyOnWrite 容器只能保证数据最终的一致性,不能保证数据实时一致性。鉴于它的这些缺点,可以使用 ConcurrentHashMap 容器。 实现原理:新增到容器的数据会放到一个新的容器中,然后将原容器的引用指向新容器,旧容器也会存在,因此会有两个容器占用内存。我们也可以用同样的方式实现自己的 CopyOnWriteMap
  4. ConcurrentHashMap ConcurrentHashMap 同样是一个并发容器,将同步粒度最小化。 实现原理:ConcurrentHashMap 默认是由 16 个 Segment 组成,每个 Segment 由多个 Hashtable 组成,数据变更需要经过两次哈希算法,第一次哈希定位到 Segment,第二次哈希定位到 Segment 下的 Hashtable,容器只会将单个 Segment 锁住,然后操作 Segment 下的 Hashtable,多个 Segment 之间不受影响。如果需要扩容不是对 Segment 扩容而是对 Segment 下的 Hashtable 扩容。虽然经过两次哈希算法会使效率降低,但是比锁住整个容器效率要高得多。
  5. BlockingQueue BlockingQueue 只是一个接口,它的实现类有 ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueueSynchronousQueueDelayQueueLinkedBlockingDeque
    • ArrayBlockingQueue:由数据支持的有界阻塞队列。
    • LinkedBlockingQueue:基于链接节点、范围任意的阻塞队列。
    • PriorityBlockingQueue:无界阻塞队列。
    • SynchronousQueue:一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作。
    • DelayQueueDelayed 元素的一个无界阻塞队列。
    • LinkedBlockingDeque:基于链接节点、范围任意的双端阻塞队列,可以在队列的两端添加、移除元素。
  6. Lock Lock 分为公平锁和非公平锁,默认是非公平锁。实现类有 ReentrantLockReentrantReadWriteLock,都依赖于 AbstractQueuedSynchronizer 抽象类。ReentrantLock 将所有 Lock 接口的操作都委派到 Sync 类上,Sync 有两个子类:NonFairSyncFairSync,通过其命名就能知道分别处理非公平锁和公平锁的。AbstractQueuedSynchronizer 把所有请求构成一个 CLH 队列,这里是一个虚拟队列,当有线程竞争锁时,该线程会首先尝试是否能获取锁,这种做法对于在队列中等待的线程来说是非公平的,如果有线程正在 Running,那么通过循环的 CAS 操作将此线程增加到队尾,直至添加成功。
  7. Atomic包 Atomic 包下的类实现了原子操作,有对基本类型如 intlongboolean 实现原子操作的类:AtomicIntegerAtomicLongAtomicBoolean,如果需要对一个对象进行原子操作,也有对对象引用进行原子操作的 AtomicReference 类,还有对对象数组操作的原子类:AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray。原子操作核心思想是 CAS 操作,然后调用底层操作系统指令来实现。

JAVA并发编程实战怎么样

我不想再继续吐槽翻译,的确有些话理解起来有些费劲,但就内容而言,这本书当吃无愧堪称 JAVA 并发领域的一朵明珠,光芒万丈的指引着并发这条路。(如果你有能力就读英文版的,既然要吐槽中文版,还是就事论事的好) 前年的时候看过一边,当时觉得读这本书的时候用个新的成语来形容就是——不明觉厉。近两年各种并发开始流行,其实也流行了几十年了,可以负责任的说网上你能看到的几乎所有中文关于 JAVA 并发的理解和解读几乎都可以在这本书上找到。 个人感觉还是应该上来介绍 JMM 的,这样至少能提起很大兴趣。此书的翻译堪称晦涩难懂,如果不是硬着头皮读下来,尝试去理解,这真不是水平的问题,真难以想象花了 10 几个小时愣是把这本书再次读完了。 其实这本书读完后你最大的收获应该是能够去理解那些现今相当牛逼的 JAVA 领域的并发库和框架了,当然你的收获还有就是特别小心的使用锁,发布可见性,活跃性,性能和测试等等。这本书包含的内容涉及之广、之深不能全部一下子消化完,例子非常具有代表性和针对性,值得你面对并发时再次读读这本书,如果接触的不多或者只是刚刚了解并发,也非常适合你对整个 JAVA 世界的并发领域有个认识,重读会有更进一步的理解,JAVA 的并发真是令人瞠目结舌,无法形容,强大和灵活到一定地步了,当然这份强大是用庞大付出代价的。 个人感觉看完后,真是应该再把 JDK 里关于并发的库仔细读读。虽然这本书是在讲 JAVA 的并发,但是如果有别的语言经验的同学也应该推荐读读,让你了解下 JAVA 世界的并发是如此的精彩和复杂诡异。 虽然不能完全记住书中的细节,但建好索引就足够了,待日后用时可以再次翻阅。

java并发集合有哪些

  1. 常用的并发集合类
    • ConcurrentHashMap:线程安全的 HashMap 的实现。
    • CopyOnWriteArrayList:线程安全且在读操作时无锁的 ArrayList。
    • CopyOnWriteArraySet:基于 CopyOnWriteArrayList,不添加重复元素。
    • ArrayBlockingQueue:基于数组、先进先出、线程安全,可实现指定时间的阻塞读写,并且容量可以限制。
    • LinkedBlockingQueue:基于链表实现,读写各用一把锁,在高并发读写操作都多的情况下,性能优于 ArrayBlockingQueue
  2. 原子类
    • AtomicInteger:线程安全的 Integer,基于 CAS(无阻塞,CPU 原语),优于使用同步锁的 Integer。
  3. 线程池
    • ThreadPoolExecutor:一个高效的支持并发的线程池,可以很容易的将一个实现了 Runnable 接口的任务放入线程池执行,但要用好这个线程池,必须合理配置 corePoolSize、最大线程数、任务缓冲队列,以及队列满了+线程池满时的回绝策略,一般而言对于这些参数的配置,需考虑两类需求:高性能和缓冲执行。
    • Executor:提供了一些方便的创建 ThreadPoolExecutor 的方法。
    • FutureTask:可用于异步获取执行结果或取消执行任务的场景,基于 CAS,避免锁的使用。
    • ReentrantLock:与 synchronized 效果一致,但是又更加灵活,支持公平/非公平锁、支持可中断的锁、支持非阻塞的 tryLock(可超时)、支持锁条件等,需要手工释放锁,基于 AbstractQueueSynchronizer
    • ReentrantReadWriteLock:与 ReentrantLock 没有关系,采用两把锁,用于读多写少的情形。

JAVA如何写一个纯并发的压力测试

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ConcurrentTest {
    private static int thread_num = 200;
    private static int client_num = 460;
    private static Map keywordMap = new HashMap();
    static {
        try {
            InputStreamReader isr = new InputStreamReader(new FileInputStream(
                    new File("clicks.txt")), "GBK");
            BufferedReader buffer = new BufferedReader(isr);
            String line = "";
            while ((line = buffer.readLine()) != null) {
                keywordMap.put(line.substring(0, line.lastIndexOf(":")), "");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        int size = keywordMap.size();
        ExecutorService exec = Executors.newCachedThreadPool();
        final Semaphore semp = new Semaphore(thread_num);
        for (int index = 0; index < client_num; index++) {
            final int NO = index;
            Runnable run = new Runnable() {
                public void run() {
                    try {
                        semp.acquire();
                        System.out.println("Thread:" + NO);
                        String host = "?";
                        String para = "method=getQueryResultpageNum=1pageSize=5"
                                + "queryKeyWord="
                                + getRandomSearchKey(NO)
                                + "questionID=-1questionIdPath=-1searchType=1"
                                + "proLine=proSeries=proType=" + NO;
                        System.out.println(host + para);
                        URL url = new URL(host);
                        HttpURLConnection connection = (HttpURLConnection) url
                                .openConnection();
                        connection.setDoOutput(true);
                        connection.setDoInput(true);
                        PrintWriter out = new PrintWriter(connection
                                .getOutputStream());
                        out.print(para);
                        out.flush();
                        out.close();
                        BufferedReader in = new BufferedReader(
                                new InputStreamReader(connection
                                        .getInputStream()));
                        String line = "";
                        String result = "";
                        while ((line = in.readLine()) != null) {
                            result += line;
                        }
                        System.out.println("第:" + NO + " 个");
                        semp.release();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            exec.execute(run);
        }
        exec.shutdown();
    }
    private static String getRandomSearchKey(final int no) {
        String ret = "";
        int size = keywordMap.size();
        ret = (keywordMap.entrySet().toArray())[no].toString();
        ret = ret.substring(0, ret.lastIndexOf("="));
        System.out.println("\t" + ret);
        return ret;
    }
}