资讯专栏INFORMATION COLUMN

Java并发多线程 - 并发工具类JUC

wuyumin / 659人阅读

摘要:将屏障重置为其初始状态。注意,在由于其他原因造成损坏之后,实行重置可能会变得很复杂此时需要使用其他方式重新同步线程,并选择其中一个线程来执行重置。

安全共享对象策略

1.线程限制 : 一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改
2.共享只读 : 一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,
但是任何线程都不能修改它
3.线程安全对象 : 一个线程安全的对象或则容器,在内部通过同步机制来保证线程安全,
所以其他线程无需额外的同步就可以通过公共接口随意访问它
4.被守护对象 : 被守护对象只能通过获取特定的锁来访问

线程安全 - 同步容器

采用synchronized关键字同步,缺点 :

不能完成做到线程安全

性能差

ArrayLisy -> Vector, Stack
HashMap -> HashTable (key、value不能为null)
Collections.synchronizedXXX(List、Set、Map)

线程安全 - 并发容器 J.U.C

ArrayList -> CopyOnWriteArrayList
HashSet、TreeSet -> CopyOnWriteArraySet ConcurrentSkipListSet
HashMap、TreeMap -> ConcurrentHashMap ConcurrentSkipListMap

AbstractQueuedSynchronizer - AQS

使用Node实现FIFO队列,可以用于构建锁或则其他同步装置的基础框架

利用一个int类型表示状态

使用方法是基础

子类通过继承并通过实现它的方法管理其状态 { acquire 和 release} 的方法操纵状态

可以同时实现排他锁和共享锁模式(独占、共享)

常用类

CountDownLatch
Semaphore
CyclicBarrier
ReentrantLock
Condition
FutureTask

CountDownLacth

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有框架服务之后执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。

@Self4j
public class CountDownLatchExample {

    private final  static int threadCount = 200;
    
    public static void main(String[] arg) {
    
        ExecutorService exec = Executors.newCachedThreadPool(); 
        
        final CountDownLatch lacth = new CountDownLatch(5);
        
        for (int i = 0; i < 1000; i++) {
            exec.excute( () -> {
            final int threadNum  = i;
            try {
                test(threadNum);
            } catch (Exception e) {
                log.error("exception", e);
            } finally {
                // latch递减
                lacth.countDown();
            }
            });
        }
        // 等待latch计数器为0,则继续往下执行
        latch.await();
        // latch的await方法也可以传入等待时间,等到等待时间后不管有没完成计数都往下执行
        // latch.await( 10, TimeUnit.MILLISECONDS);
        log.info("finished");
        exec.shutdown();
    }

    public static void test(int i)  throw Exception{
        log.info("thread: {}", i);
    }
}
Semaphore

Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。
Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。
void acquire():从此信号量获取一个许可前线程将一直阻塞。
void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。
void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。
void release(int n):释放n个许可。
int availablePermits():获取当前可用的许可数。
boolean tryAcquire():仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
boolean tryAcquire(int permits):仅在调用时此信号量中有给定数目的许可时,才从此信号量中获取这些许可。

boolean tryAcquire(int permits,
                          long timeout,
                          TimeUnit unit)
                   throws InterruptedException

如果在给定的等待时间内此信号量有可用的所有许可,并且当前线程未被 中断,则从此信号量获取给定数目的许可。

@Self4j
public class SemaphoreExample {

    private final  static int threadCount = 200;

    public static void main(String[] arg) {

        ExecutorService exec = Executors.newCachedThreadPool(); 
    
        final Semaphore semaphore = new Semaphore(3);
    
        for (int i = 0; i < threadCount; i++) {
            exec.excute( () )-> {
            final int threadNum  = i;
            try {
                // tryAcquire会尝试去获取一个信号量,如果获取不到
                // 则什么都不会发生,走接下来的逻辑
                // if (semaphore.tryAcquire(1)) {
                //    test(i);
                //    semaphore.release();//释放一个信号量
                // }
                semaphore.acquire();//获取一个信号量
                test(i);
                semaphore.release();//释放一个信号量
            } catch (Exception e) {
                log.error("exception", e);
            } 
            });
        }
        log.info("finished");
        exec.shutdown();
    }

    public static void test(int i)  throw Exception{
        log.info("thread: {}", i);
    }
}
CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。

CyclicBarrier(int parties, Runnable barrierAction)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。

CyclicBarrier(int parties)
创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。

int await()
在所有 参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。

int await(long timeout,
                 TimeUnit unit)
          throws InterruptedException,
                 BrokenBarrierException,
                 TimeoutException

在所有 参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。

boolean isBroken() : 查询此屏障是否处于损坏状态。

void reset() :
将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个 BrokenBarrierException。注意,在由于其他原因造成损坏 之后,实行重置可能会变得很复杂;此时需要使用其他方式重新同步线程,并选择其中一个线程来执行重置。与为后续使用创建一个新 barrier 相比,这种方法可能更好一些。

int getNumberWaiting() :返回当前在屏障处等待的参与者数目。此方法主要用于调试和断言。

@Self4j
public class CyclicBarrierExample {

    private final  static int threadCount = 200;
    
    private final static CyclicBarrier cyclicBarrier = new CyclicBarrier(7, 
        () -> {
        log.info("callback is running !");
        }
    );
    
    public static void main(String[] arg) {
    
        ExecutorService exec = Executors.newCachedThreadPool(); 
        
        for (int i = 0; i < threadCount; i++) {
            exec.excute( () -> {
                final int threadNum  = i;
                try {
                    race(i);
                } catch (Exception e) {
                    log.error("exception", e);
                } 
            });
        }
        log.info("finished");
        
        exec.shutdown();
    }
    
    public static void race(int i)  throw Exception{
        log.info("thread {} is ready", i);
        cyclicBarrier.await();
        log.info("thread {} is continue", i);
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72969.html

相关文章

  • Java线程进阶(一)—— J.U.C并发包概述

    摘要:整个包,按照功能可以大致划分如下锁框架原子类框架同步器框架集合框架执行器框架本系列将按上述顺序分析,分析所基于的源码为。后,根据一系列常见的多线程设计模式,设计了并发包,其中包下提供了一系列基础的锁工具,用以对等进行补充增强。 showImg(https://segmentfault.com/img/remote/1460000016012623); 本文首发于一世流云专栏:https...

    anonymoussf 评论0 收藏0
  • java并发系列 - 第21天:java中的CAS操作,java并发的基石

    摘要:方法由两个参数,表示期望的值,表示要给设置的新值。操作包含三个操作数内存位置预期原值和新值。如果处的值尚未同时更改,则操作成功。中就使用了这样的操作。上面操作还有一点是将事务范围缩小了,也提升了系统并发处理的性能。 这是java高并发系列第21篇文章。 本文主要内容 从网站计数器实现中一步步引出CAS操作 介绍java中的CAS及CAS可能存在的问题 悲观锁和乐观锁的一些介绍及数据库...

    zorro 评论0 收藏0
  • java并发系列 - 第19天:JUC中的Executor框架详解1,全面掌握java并发相关技术

    摘要:有三种状态运行关闭终止。类类,提供了一系列工厂方法用于创建线程池,返回的线程池都实现了接口。线程池的大小一旦达到最大值就会保持不变,在提交新任务,任务将会进入等待队列中等待。此线程池支持定时以及周期性执行任务的需求。 这是java高并发系列第19篇文章。 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadP...

    icattlecoder 评论0 收藏0
  • JAVA并发编程之-Volatile关键字及内存可见性

    摘要:的缺点频繁刷新主内存中变量,可能会造成性能瓶颈不具备操作的原子性,不适合在对该变量的写操作依赖于变量本身自己。 作者:毕来生微信:878799579 1. 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1、如果一个变量被volatile关键字修饰,那么这个变量对所有线程都是可见的。2、如果某条线程修...

    xcold 评论0 收藏0
  • Java JUC学习 - ConcurrentLinkedDeque 详解

    摘要:概述是从开始提供的一种非阻塞式线程安全链表,隶属于包。当许多线程同时访问一个公共集合时,是一个合适的选择。程序的一次输出为该程序实现了多线程并发添加大量元素到一个公共的链表,刚好是的典型使用场景。 Java JUC学习 - ConcurrentLinkedDeque 详解 0x00 前言 如何实现并发程序,对于Java以及其他高级语言来说都是一件并不容易的事情。在大一上学期的时候,我们...

    Drummor 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<