`

Concurrent - 并发框架

 
阅读更多

原创转载请注明出处:http://agilestyle.iteye.com/blog/2356899

 

SynchronizedMap和ConcurrentHashMap有什么区别?

后者具有更高的并发

SynchronizedMap锁的是整个对象

ConcurrentHashMap锁的是段
...   
   /**
     * Maps the specified key to the specified value in this table.
     * Neither the key nor the value can be null.
     *
     * <p>The value can be retrieved by calling the {@code get} method
     * with a key that is equal to the original key.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with {@code key}, or
     *         {@code null} if there was no mapping for {@code key}
     * @throws NullPointerException if the specified key or value is null
     */
    public V put(K key, V value) {
        return putVal(key, value, false);
    }

    /** Implementation for put and putIfAbsent */
    final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }
            else if ((fh = f.hash) == MOVED)
                tab = helpTransfer(tab, f);
            else {
                V oldVal = null;
                synchronized (f) {
                    if (tabAt(tab, i) == f) {
                        if (fh >= 0) {
                            binCount = 1;
                            for (Node<K,V> e = f;; ++binCount) {
                                K ek;
                                if (e.hash == hash &&
                                    ((ek = e.key) == key ||
                                     (ek != null && key.equals(ek)))) {
                                    oldVal = e.val;
                                    if (!onlyIfAbsent)
                                        e.val = value;
                                    break;
                                }
                                Node<K,V> pred = e;
                                if ((e = e.next) == null) {
                                    pred.next = new Node<K,V>(hash, key,
                                                              value, null);
                                    break;
                                }
                            }
                        }
                        else if (f instanceof TreeBin) {
                            Node<K,V> p;
                            binCount = 2;
                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                           value)) != null) {
                                oldVal = p.val;
                                if (!onlyIfAbsent)
                                    p.val = value;
                            }
                        }
                    }
                }
                if (binCount != 0) {
                    if (binCount >= TREEIFY_THRESHOLD)
                        treeifyBin(tab, i);
                    if (oldVal != null)
                        return oldVal;
                    break;
                }
            }
        }
        addCount(1L, binCount);
        return null;
    }
...

Note:

ConcurrentHashMap 的结构示意图

ConcurrentHashMap 在默认并发级别会创建包含 16 个 Segment 对象的数组。每个 Segment 的成员对象 table 包含若干个散列表的桶。每个桶是由 HashEntry 链接起来的一个链表。如果键能均匀散列,每个 Segment 大约守护整个散列表中桶总数的 1/16。

 

CopyOnWriteArrayList可以用于什么应用场景?

多读少写

...    
   /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (index > len || index < 0)
                throw new IndexOutOfBoundsException("Index: "+index+
                                                    ", Size: "+len);
            Object[] newElements;
            int numMoved = len - index;
            if (numMoved == 0)
                newElements = Arrays.copyOf(elements, len + 1);
            else {
                newElements = new Object[len + 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index, newElements, index + 1,
                                 numMoved);
            }
            newElements[index] = element;
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }
...

 

如何合理的配置Java线程池?如CPU密集型的任务,基本线程池应该配置多大?IO密集型的任务,基本线程池应该配置多大?用有界队列好还是无界队列好?任务非常多的时候,使用什么阻塞队列能获取最好的吞吐量?

要想合理的配置线程池,就必须首先分析任务特性,可以从以下几个角度来进行分析:

 

任务的性质:CPU密集型任务,IO密集型任务和混合型任务。

任务的优先级:高,中和低。

任务的执行时间:长,中和短。

任务的依赖性:是否依赖其他系统资源,如数据库连接。

任务性质不同的任务可以用不同规模的线程池分开处理。

  • CPU密集型任务配置尽可能少的线程数量,如配置Ncpu+1个线程的线程池。
  • IO密集型任务则由于需要等待IO操作,线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。
  • 混合型的任务,如果可以拆分,则将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。我们可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。

优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先得到执行,需要注意的是如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。

 

执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。

 

依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,如果等待的时间越长CPU空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用CPU。

 

建议使用有界队列,有界队列能增加系统的稳定性和预警能力,可以根据需要设大一点,比如几千。有一次我们组使用的后台任务线程池的队列和线程池全满了,不断的抛出抛弃任务的异常,通过排查发现是数据库出现了问题,导致执行SQL变得非常缓慢,因为后台任务线程池里的任务全是需要向数据库查询和插入数据的,所以导致线程池里的工作线程全部阻塞住,任务积压在线程池里。如果当时我们设置成无界队列,线程池的队列就会越来越多,有可能会撑满内存,导致整个系统不可用,而不只是后台任务出现问题。当然我们的系统所有的任务是用的单独的服务器部署的,而我们使用不同规模的线程池跑不同类型的任务,但是出现这样问题时也会影响到其他任务。

http://ifeve.com/thread-pools/

http://ifeve.com/java-threadpool/

 

  • 大小: 93.7 KB
  • 大小: 21.4 KB
分享到:
评论

相关推荐

    concurrent-all-in-one.pdf

    13. **Fork/Join框架** - ForkJoinPool:处理并行任务的线程池。 - ForkJoinTask:可拆分的任务,支持递归分解。 14. **并发工具** - CountDownLatch、CyclicBarrier、Semaphore等,用于线程间协调,解决并发...

    backport-util-concurrent-3.1.jar和geronimo-stax-api_1.0_spec-1.0.1.jar

    总的来说,这两个jar文件是为了解决在使用Eclipse Axis2 Codegen插件时遇到的依赖问题,特别是对于Java 5之前的环境,"backport-util-concurrent-3.1.jar"提供必要的并发工具,而"geronimo-stax-api_1.0_spec-1.0.1....

    java.util.concurrent-多线程框架.docx

    在 java.util.concurrent 多线程框架中,还提供了多种其他机制,包括并发集合、同步器、lock 等,以便开发者更方便地编写高效、可靠的多线程程序。并发集合提供了多种机制,包括 CopyOnWriteArrayList、...

    concurrent-1.3.4.jar

    线程池:concurrent包提供了Executor框架,可以方便地创建和管理线程池,从而更好地控制并发线程的数量,避免线程创建和销毁的开销。 同步工具类:concurrent包提供了一些同步工具类,如CountDownLatch、...

    concurrent-1.3.2 connector.

    在IT行业中,"concurrent-1.3.2 connector" 提到的是一个特定版本的并发连接器,可能是某个软件框架或库的一部分。这个版本号(1.3.2)表明这是一个迭代更新,通常包含了错误修复、性能提升或者新功能的添加。在...

    Java-concurrent-collections-concurrenthashmap-blockingqueue.pdf

    Java 并发集合是 Java 语言中的一种高级hread-safe 集合框架,用于在多线程环境中实现高效、安全的数据存储和访问。其中,ConcurrentHashMap 和 BlockingQueue 是两种常用的并发集合类型,它们提供了高效的并发操作...

    Java-并发(Concurrent)编程

    Java并发编程是开发高效应用程序的关键技能之一,尤其在如今的多核处理器环境下,理解并熟练掌握并发技术至关重要。本文将深入探讨并发编程的核心概念、工具和实现机制。 首先,我们来了解一下多线程。多线程是编程...

    java自带并发框架

    Java并发框架是Java JDK中内置的一系列用于处理多线程并行执行的工具和类库,自JDK 5.0引入以来,极大地简化了并发编程的复杂性。这个框架由Doug Lea设计,并在JSR-166任务中提出,最终在Tiger(JDK 5)版本中被引入...

    Concurrent-programming:并发编程分配

    Java还引入了`ExecutorService`,这是Java并发框架的一部分,它提供了线程池管理,可以更有效地管理和控制线程。`ExecutorService`可以通过`Executors`类的静态工厂方法创建,比如`newFixedThreadPool`用于创建固定...

    Java-Executor并发框架.docx

    Java并发框架中的Executor服务是Java 1.5引入的核心组件,位于`java.util.concurrent`包下,极大地简化了多线程编程。Executor接口虽然历史悠久,但其重要性不言而喻,很多开发者对其背后的原理并不十分了解。本文将...

    《Java并发编程高阶技术-高性能并发框架源码解析与实战》学习.zip

    本书的焦点在于Java并发框架,这些框架如线程池(java.util.concurrent.ThreadPoolExecutor)、并发集合(ConcurrentHashMap、CopyOnWriteArrayList等)以及同步工具类(Semaphore、CyclicBarrier、CountDownLatch等...

    Java并发框架整理

    ### Java并发框架整理 #### 多线程从1.2到1.7各种接口使用及场景介绍 在Java中,多线程技术是一项非常重要的功能,它可以极大地提高应用程序的性能和响应能力。从JDK 1.2版本开始,Java就提供了支持多线程的基础...

    Concurrent-MultiThread-Async:多线程的使用,concurrent包的使用,并发队列的时候,@ Async方法返回值的异步处理,

    `concurrent`包提供了一系列高级并发工具,如线程池、并发容器、同步器等,帮助开发者更好地管理和控制并发执行。例如: - `ExecutorService`和`ThreadPoolExecutor`:用于创建和管理线程池,可以有效地复用线程,...

    join-1.13-h-2.zip

    在Junit测试框架的基础上,该库提供了一系列工具和注解,帮助开发者创建和执行并发测试,确保代码在多线程环境中的正确性和稳定性。 首先,我们来看一下"meles-concurrent-testing"的核心特性。它引入了一个名为`@...

    Java-并发PPT课件.ppt

    Java并发编程的核心组件是Java并发工具包(JUC),它提供了丰富的类和接口,如synchronized、volatile、java.util.concurrent.atomic包下的原子类等,用于保证线程安全和内存一致性。synchronized关键字用于实现互斥...

    concurrent-merge-sort

    基本的Spring IoC框架。 3.使用日志记录。 相同算法有两种不同的实现方式来演示并发实现。 第一个是edu.ncsu.mhthakka.concurrent.callable.mergesort.CallableMergeSorter这是一个实现合并排序的类。 它使用java的...

    并发框架

    并发框架是计算机编程中用于处理多线程和并行计算的一种结构化方法。在现代多核处理器环境下,并发编程已经成为优化应用性能、提高系统资源利用率的关键技术。并发框架提供了管理和协调多个执行线程的工具和机制,...

    OC- 并发队列在同步线程中执行

    并发队列是苹果的Grand Central Dispatch (GCD)框架中的一个关键概念,用于优化应用程序性能,尤其是在处理大量数据或进行耗时操作时。在本文中,我们将深入探讨如何在同步线程中使用并发队列,以及它们的工作原理和...

Global site tag (gtag.js) - Google Analytics