java的concurrent用法详解

鸿蒙NEXT(开发进阶)@Concurrent装饰器并发函数 ​ 在使用TaskPool时,执行的并发函数需要使用该装饰器修饰,否则无法通过相关校验。 ​ 阅读详情
 
        我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便。而当针对高质量Java多线程并发程序设计时,为防止死蹦等现象的出现,比如使用java之前的wait()、notify()和synchronized等,每每需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等诸多因素,往往会采用一些较为复杂的安全策略,加重了程序员的开发负担.万幸的是,在JDK1.5出现之后,Sun大神(Doug Lea)终于为我们这些可怜的小程序员推出了java.util.concurrent工具包以简化并发完成。开发者们借助于此,将有效的减少竞争条件(race conditions)和死锁线程。concurrent包很好的解决了这些问题,为我们提供了更实用的并发程序模型。

Executor                  :具体Runnable任务的执行者。
ExecutorService           :一个线程池管理者,其实现类有多种,我会介绍一部分。我们能把Runnable,Callable提交到池中让其调度。
Semaphore                 :一个计数信号量
ReentrantLock             :一个可重入的互斥锁定 Lock,功能类似synchronized,但要强大的多。
Future                    :是与Runnable,Callable进行交互的接口,比如一个线程执行结束后取返回的结果等等,还提供了cancel终止线程。
BlockingQueue             :阻塞队列。
CompletionService         : ExecutorService的扩展,可以获得线程执行结果的
CountDownLatch            :一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 
CyclicBarrier             :一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 
Future                    :Future 表示异步计算的结果。
ScheduledExecutorService :一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令。
接下来逐一介绍
Executors主要方法说明
newFixedThreadPool(固定大小线程池)
创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程(只有要请求的过来,就会在一个队列里等待执行)。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。
newCachedThreadPool(无界线程池,可以进行自动线程回收)
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。
newSingleThreadExecutor(单个后台线程)
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
这些方法返回的都是ExecutorService对象,这个对象可以理解为就是一个线程池。
这个线程池的功能还是比较完善的。可以提交任务submit()可以结束线程池shutdown()。
01 import java.util.concurrent.ExecutorService;
02 import java.util.concurrent.Executors;
03 public class MyExecutor extends Thread {
04 private int index;
05 public MyExecutor(int i){
06     this.index=i;
07 }
08 public void run(){
09     try{
10      System.out.println("["+this.index+"] start....");
11      Thread.sleep((int)(Math.random()*1000));
12      System.out.println("["+this.index+"] end.");
13     }
14     catch(Exception e){
15      e.printStackTrace();
16     }
17 }
18 public static void main(String args[]){
19     ExecutorService service=Executors.newFixedThreadPool(4);
20     for(int i=0;i<10;i++){
21      service.execute(new MyExecutor(i));
22      //service.submit(new MyExecutor(i));
23     }
24     System.out.println("submit finish");
25     service.shutdown();
26 }
27 }

虽然打印了一些信息,但是看的不是非常清晰,这个线程池是如何工作的,我们来将休眠的时间调长10倍。
Thread.sleep((int)(Math.random()*10000));
再来看,会清楚看到只能执行4个线程。当执行完一个线程后,才会又执行一个新的线程,也就是说,我们将所有的线程提交后,线程池会等待执行完最后shutdown。我们也会发现,提交的线程被放到一个“无界队列里”。这是一个有序队列(BlockingQueue,这个下面会说到)。
另外它使用了Executors的静态函数生成一个固定的线程池,顾名思义,线程池的线程是不会释放的,即使它是Idle。
这就会产生性能问题,比如如果线程池的大小为200,当全部使用完毕后,所有的线程会继续留在池中,相应的内存和线程切换(while(true)+sleep循环)都会增加。
如果要避免这个问题,就必须直接使用ThreadPoolExecutor()来构造。可以像通用的线程池一样设置“最大线程数”、“最小线程数”和“空闲线程keepAlive的时间”。

这个就是线程池基本用法。
Semaphore
一个计数信号量。从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。例如,下面的类使用信号量控制对内容池的访问:
这里是一个实际的情况,大家排队上厕所,厕所只有两个位置,来了10个人需要排队。
01 import java.util.concurrent.ExecutorService;
02 import java.util.concurrent.Executors;
03 import java.util.concurrent.Semaphore;
04 public class MySemaphore extends Thread {
05 Semaphore position;
06 private int id;
07 public MySemaphore(int i,Semaphore s){
08     this.id=i;
09     this.position=s;
10 }
11 public void run(){
12     try{
13      if(position.availablePermits()>0){
14       System.out.println("顾客["+this.id+"]进入厕所,有空位");
15      }
16      else{
17       System.out.println("顾客["+this.id+"]进入厕所,没空位,排队");
18      }
19      position.acquire();
20      System.out.println("顾客["+this.id+"]获得坑位");
21      Thread.sleep((int)(Math.random()*1000));
22      System.out.println("顾客["+this.id+"]使用完毕");
23      position.release();
24     }
25     catch(Exception e){
26      e.printStackTrace();
27     }
28 }
29 public static void main(String args[]){
30     ExecutorService list=Executors.newCachedThreadPool();
31     Semaphore position=new Semaphore(2);
32     for(int i=0;i<10;i++){
33      list.submit(new MySemaphore(i+1,position));
34     }
35     list.shutdown();
36     position.acquireUninterruptibly(2);
37     System.out.println("使用完毕,需要清扫了");
38     position.release(2);
39 }
40 }
ReentrantLock
一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。
ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平参数。
当设置为 true时,在多个线程的争用下,这些锁定倾向于将访问权授予等待时间最长的线程。否则此锁定将无法保证任何特定访问顺序。
与采用默认设置(使用不公平锁定)相比,使用公平锁定的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁定和保证锁定分配的均衡性时差异较小。不过要注意的是,公平锁定不能保证线程调度的公平性。因此,使用公平锁定的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁定时。还要注意的是,未定时的 tryLock 方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁定是可用的,此方法就可以获得成功。
建议总是 立即实践,使用 try 块来调用 lock,在之前/之后的构造中,最典型的代码如下: 
01 class X {
02     private final ReentrantLock lock = new ReentrantLock();
03     // ...
04     public void m() {
05       lock.lock(); // block until condition holds
06       try {
07         // ... method body
08       } finally {
09         lock.unlock()
10       }
11     }
12 }
我的例子:
01 import java.util.concurrent.ExecutorService;
02 import java.util.concurrent.Executors;
03 import java.util.concurrent.locks.ReentrantLock;
04 public class MyReentrantLock extends Thread{
05 TestReentrantLock lock;
06 private int id;
07 public MyReentrantLock(int i,TestReentrantLock test){
08     this.id=i;
09     this.lock=test;
10 }
11 public void run(){
12     lock.print(id);
13 }
14 public static void main(String args[]){
15     ExecutorService service=Executors.newCachedThreadPool();
16     TestReentrantLock lock=new TestReentrantLock();
17     for(int i=0;i<10;i++){
18      service.submit(new MyReentrantLock(i,lock));
19     }
20     service.shutdown();
21 }
22 }
23 class TestReentrantLock{
24 private ReentrantLock lock=new ReentrantLock();
25 public void print(int str){
26     try{
27      lock.lock();
28      System.out.println(str+"获得");
29      Thread.sleep((int)(Math.random()*1000));
30     }
31     catch(Exception e){
32      e.printStackTrace();
33     }
34     finally{
35      System.out.println(str+"释放");
36      lock.unlock();
37     }
38 }
39 }
BlockingQueue
支持两个附加操作的 Queue,这两个操作是:检索元素时等待队列变为非空,以及存储元素时等待空间变得可用。
BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示 poll 操作失败的警戒值。
BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个 remainingCapacity,超出此容量,便无法无阻塞地 put 额外的元素。
没有任何内部容量约束的 BlockingQueue 总是报告 Integer.MAX_VALUE 的剩余容量。
BlockingQueue 实现主要用于生产者-使用者队列,但它另外还支持 Collection 接口。因此,举例来说,使用 remove(x) 从队列中移除任意一个元素是有可能的。
然而,这种操作通常不 会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。
BlockingQueue 实现是线程安全的。所有排队方法都可以使用内部锁定或其他形式的并发控制来自动达到它们的目的。
然而,大量的 Collection 操作(addAll、containsAll、retainAll 和 removeAll)没有 必要自动执行,除非在实现中特别说明。
因此,举例来说,在只添加了 c 中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
BlockingQueue 实质上不 支持使用任何一种“close”或“shutdown”操作来指示不再添加任何项。
这种功能的需求和使用有依赖于实现的倾向。例如,一种常用的策略是:对于生产者,插入特殊的 end-of-stream 或 poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
下面的例子演示了这个阻塞队列的基本功能。
01 import java.util.concurrent.BlockingQueue;
02 import java.util.concurrent.ExecutorService;
03 import java.util.concurrent.Executors;
04 import java.util.concurrent.LinkedBlockingQueue;
05 public class MyBlockingQueue extends Thread {
06 public static BlockingQueue<String> queue = new LinkedBlockingQueue<String>(3);
07 private int index;
08 public MyBlockingQueue(int i) {
09    this.index = i;
10 }
11 public void run() {
12    try {
13     queue.put(String.valueOf(this.index));
14     System.out.println("{" + this.index + "} in queue!");
15    } catch (Exception e) {
16     e.printStackTrace();
17    }
18 }
19 public static void main(String args[]) {
20    ExecutorService service = Executors.newCachedThreadPool();
21    for (int i = 0; i < 10; i++) {
22     service.submit(new MyBlockingQueue(i));
23    }
24    Thread thread = new Thread() {
25     public void run() {
26      try {
27       while (true) {
28        Thread.sleep((int) (Math.random() * 1000));
29        if(MyBlockingQueue.queue.isEmpty())
30         break;
31        String str = MyBlockingQueue.queue.take();
32        System.out.println(str + " has take!");
33       }
34      } catch (Exception e) {
35       e.printStackTrace();
36      }
37     }
38    };
39    service.submit(thread);
40    service.shutdown();
41 }
42 }
---------------------执行结果-----------------
{0} in queue!
{1} in queue!
{2} in queue!
{3} in queue!
0 has take!
{4} in queue!
1 has take!
{6} in queue!
2 has take!
{7} in queue!
3 has take!
{8} in queue!
4 has take!
{5} in queue!
6 has take!
{9} in queue!
7 has take!
8 has take!
5 has take!
9 has take!
-----------------------------------------

CompletionService
将生产新的异步任务与使用已完成任务的结果分离开来的服务。生产者 submit 执行的任务。使用者 take 已完成的任务,
并按照完成这些任务的顺序处理它们的结果。例如,CompletionService 可以用来管理异步 IO ,执行读操作的任务作为程序或系统的一部分提交,
然后,当完成读操作时,会在程序的不同部分执行其他操作,执行操作的顺序可能与所请求的顺序不同。
通常,CompletionService 依赖于一个单独的 Executor 来实际执行任务,在这种情况下,
CompletionService 只管理一个内部完成队列。ExecutorCompletionService 类提供了此方法的一个实现。

01 import java.util.concurrent.Callable;
02 import java.util.concurrent.CompletionService;
03 import java.util.concurrent.ExecutorCompletionService;
04 import java.util.concurrent.ExecutorService;
05 import java.util.concurrent.Executors;
06 public class MyCompletionService implements Callable<String> {
07 private int id;
08  
09 public MyCompletionService(int i){
10    this.id=i;
11 }
12 public static void main(String[] args) throws Exception{
13    ExecutorService service=Executors.newCachedThreadPool();
14    CompletionService<String> completion=new ExecutorCompletionService<String>(service);
15    for(int i=0;i<10;i++){
16     completion.submit(new MyCompletionService(i));
17    }
18    for(int i=0;i<10;i++){
19     System.out.println(completion.take().get());
20    }
21    service.shutdown();
22 }
23 public String call() throws Exception {
24    Integer time=(int)(Math.random()*1000);
25    try{
26     System.out.println(this.id+" start");
27     Thread.sleep(time);
28     System.out.println(this.id+" end");
29    }
30    catch(Exception e){
31     e.printStackTrace();
32    }
33    return this.id+":"+time;
34 }
35 }

CountDownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。
之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。
CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,
或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。
用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。
CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,
而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await。 
一下的例子是别人写的,非常形象。
01 import java.util.concurrent.CountDownLatch;
02 import java.util.concurrent.ExecutorService;
03 import java.util.concurrent.Executors;
04 public class TestCountDownLatch {
05 public static void main(String[] args) throws InterruptedException {
06    // 开始的倒数锁
07    final CountDownLatch begin = new CountDownLatch(1);
08    // 结束的倒数锁
09    final CountDownLatch end = new CountDownLatch(10);
10    // 十名选手
11    final ExecutorService exec = Executors.newFixedThreadPool(10);
12    
13    for (int index = 0; index < 10; index++) {
14     final int NO = index + 1;
15     Runnable run = new Runnable() {
16      public void run() {
17       try {
18        begin.await();//一直阻塞
19        Thread.sleep((long) (Math.random() * 10000));
20        System.out.println("No." + NO + " arrived");
21       } catch (InterruptedException e) {
22       } finally {
23        end.countDown();
24       }
25      }
26     };
27     exec.submit(run);
28    }
29    System.out.println("Game Start");
30    begin.countDown();
31    end.await();
32    System.out.println("Game Over");
33    exec.shutdown();
34 }
35 }

CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了。

CyclicBarrier
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。
在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),
该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。
示例用法:下面是一个在并行分解设计中使用 barrier 的例子,很经典的旅行团例子:
01 import java.text.SimpleDateFormat;
02 import java.util.Date;
03 import java.util.concurrent.BrokenBarrierException;
04 import java.util.concurrent.CyclicBarrier;
05 import java.util.concurrent.ExecutorService;
06 import java.util.concurrent.Executors;
07 public class TestCyclicBarrier {
08   // 徒步需要的时间: Shenzhen, Guangzhou, Shaoguan, Changsha, Wuhan
09   private static int[] timeWalk = { 5, 8, 15, 15, 10 };
10   // 自驾游
11   private static int[] timeSelf = { 1, 3, 4, 4, 5 };
12   // 旅游大巴
13   private static int[] timeBus = { 2, 4, 6, 6, 7 };
14    
15   static String now() {
16      SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
17      return sdf.format(new Date()) + ": ";
18   }
19   static class Tour implements Runnable {
20      private int[] times;
21      private CyclicBarrier barrier;
22      private String tourName;
23      public Tour(CyclicBarrier barrier, String tourName, int[] times) {
24        this.times = times;
25        this.tourName = tourName;
26        this.barrier = barrier;
27      }
28      public void run() {
29        try {
30          Thread.sleep(times[0] * 1000);
31          System.out.println(now() + tourName + " Reached Shenzhen");
32          barrier.await();
33          Thread.sleep(times[1] * 1000);
34          System.out.println(now() + tourName + " Reached Guangzhou");
35          barrier.await();
36          Thread.sleep(times[2] * 1000);
37          System.out.println(now() + tourName + " Reached Shaoguan");
38          barrier.await();
39          Thread.sleep(times[3] * 1000);
40          System.out.println(now() + tourName + " Reached Changsha");
41          barrier.await();
42          Thread.sleep(times[4] * 1000);
43          System.out.println(now() + tourName + " Reached Wuhan");
44          barrier.await();
45        } catch (InterruptedException e) {
46        } catch (BrokenBarrierException e) {
47        }
48      }
49   }
50   public static void main(String[] args) {
51      // 三个旅行团
52      CyclicBarrier barrier = new CyclicBarrier(3);
53      ExecutorService exec = Executors.newFixedThreadPool(3);
54      exec.submit(new Tour(barrier, "WalkTour", timeWalk));
55      exec.submit(new Tour(barrier, "SelfTour", timeSelf));
56 //当我们把下面的这段代码注释后,会发现,程序阻塞了,无法继续运行下去。
57      exec.submit(new Tour(barrier, "BusTour", timeBus));
58      exec.shutdown();
59   }
60 }

CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。
Future
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
计算完成后只能使用 get 方法来检索结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。
还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。
如果为了可取消性而使用 Future但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为基础任务的结果。
这个我们在前面CompletionService已经看到了,这个Future的功能,而且这个可以在提交线程的时候被指定为一个返回对象的。

ScheduledExecutorService
一个 ExecutorService,可安排在给定的延迟后运行或定期执行的命令。
schedule 方法使用各种延迟创建任务,并返回一个可用于取消或检查执行的任务对象。scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务。
用 Executor.execute(java.lang.Runnable) 和 ExecutorService 的 submit 方法所提交的命令,通过所请求的 0 延迟进行安排。
schedule 方法中允许出现 0 和负数延迟(但不是周期),并将这些视为一种立即执行的请求。
所有的 schedule 方法都接受相对 延迟和周期作为参数,而不是绝对的时间或日期。将以 Date 所表示的绝对时间转换成要求的形式很容易。
例如,要安排在某个以后的日期运行,可以使用:schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)。
但是要注意,由于网络时间同步协议、时钟漂移或其他因素的存在,因此相对延迟的期满日期不必与启用任务的当前 Date 相符。
Executors 类为此包中所提供的 ScheduledExecutorService 实现提供了便捷的工厂方法。
一下的例子也是网上比较流行的。
01 import static java.util.concurrent.TimeUnit.SECONDS;
02 import java.util.Date;
03 import java.util.concurrent.Executors;
04 import java.util.concurrent.ScheduledExecutorService;
05 import java.util.concurrent.ScheduledFuture;
06 public class TestScheduledThread {
07 public static void main(String[] args) {
08    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
09    final Runnable beeper = new Runnable() {
10     int count = 0;
11     public void run() {
12      System.out.println(new Date() + " beep " + (++count));
13     }
14    };
15    // 1秒钟后运行,并每隔2秒运行一次
16    final ScheduledFuture beeperHandle = scheduler.scheduleAtFixedRate(beeper, 1, 2, SECONDS);
17    // 2秒钟后运行,并每次在上次任务运行完后等待5秒后重新运行
18    final ScheduledFuture beeperHandle2 = scheduler.scheduleWithFixedDelay(beeper, 2, 5, SECONDS);
19    // 30秒后结束关闭任务,并且关闭Scheduler
20    scheduler.schedule(new Runnable() {
21     public void run() {
22      beeperHandle.cancel(true);
23      beeperHandle2.cancel(true);
24      scheduler.shutdown();
25     }
26    }, 30, SECONDS);
27 }
28 }
这样我们就把concurrent包下比较重要的功能都已经总结完了,希望对我们理解能有帮助。
HarmonyOS 应用开发之@Concurrent装饰器:声明并校验并发函数 在使用 TaskPool 时,执行的并发函数需要使用该装饰器修饰,否则无法通过相关校验。从API version 9开始,该装饰器支持在ArkTS卡片中使用。 阅读详情

相关推荐

java.util.concurrent包

java.util.concurrent包是Java中用于并发编程的重要工具集,提供了丰富的并发原语和组件,以简化多线程编程的复杂性,并帮助开发者编写高效、可伸缩和线程安全的并发程序。

oopxiajun博客专栏 1177

Java 并发工具包(concurrent)详解

一、concurrent并发包 在JDK1.5之前,Java中要进行业务并发时,不管什么情况下,都需要由程序员独立完成代码实现,此时在进行一些并发设计时需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的危害等,往往会采用一些较为复杂的安全策略,加重了程序员的开发负担。.在JDK1.5出现之后,java.util.concurrent工具包作为简化并发出现。concurrent提供了多种并发模型使我们在相应的情况下大大减少了开发的负担。下面对其中常见实现类进行讲解。 ...

zcm036200的博客 1万+

Linux实战:rMATS可变剪切分析从零到一,避坑指南与结果深度解析

本文详细介绍了在Linux系统上从零开始部署rMATS进行可变剪切分析的完整流程,包括环境搭建、安装避坑指南、参数优化及结果解读。特别针对gfortran依赖、数学库配置等常见问题提供解决方案,并深入解析JC与JCEC结果的差异及可视化技巧,帮助生物信息学研究者高效完成可变剪切分析。

weixin_30394669的博客 411

java concurrent 探秘

java concurrent 探秘(转) 我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便。而当针对高质量Java多线程并发程序设计时,为防止死蹦等现象的出现,比如使用java之前的wait()、notify()和synchronized等,每每需要考虑性能、死锁...

MyKM 841

手机拍照也能玩高光谱?教你用TensorFlow Lite在Android上实现实时RGB转高光谱

本文介绍了如何利用TensorFlow Lite在Android设备上实现实时RGB到高光谱的图像重构技术。通过深度学习模型优化和移动端部署策略,使智能手机具备专业级光谱分析能力,适用于农业检测、化妆品分析等多个领域。

weixin_29091105的博客 247

OpenClaw 3.13 + Mac mini M4 集成 qmd 记忆存储:qmd embed 卡死 / 报错 sqlite-vec 不可用 终极解决教程

模型加速让 qmd 从国内镜像下载模型,避免网络超时;SQLite 扩展支持:修改 qmd 源码后,Bun 不再使用内置 SQLite,而是调用 Homebrew 安装的,该版本支持接口,可正常加载vec0.dylib向量扩展;OpenClaw 3.13 适配:核心逻辑与 OpenClaw 3.13 的 qmd 记忆调用逻辑完全兼容,无需额外调整;sqlite-vec 加载:qmd 自动通过sqlite-vec包获取vec0.dylib路径,调用完成向量扩展加载,实现高效向量搜索。

wuanxionglidui的博客 1305

java 的 concurrent 包

包为 Java 提供了强大的并发编程工具,帮助开发者在多线程环境下编写高效、健壮的程序。通过使用并发集合、线程池、同步工具类、锁和原子变量等组件,开发者可以更方便地处理并发任务,避免线程安全问题,提高应用程序的性能和可扩展性。

Flying_Fish_roe的博客 1419

多尺度Transformer+特征融合新范式,算力减半精度猛增

在大模型时代,多尺度特征融合与Transformer架构的结合正成为研究热点。多尺度特征融合能够捕捉数据在不同尺度上的关键信息,而Transformer架构凭借其强大的并行处理能力和对长距离依赖的建模能力,为复杂数据处理提供了新的思路。这种结合在处理多模态数据时展现出巨大潜力。

Tulingxueshu的博客 1061

Java的concurrent用法详解

我们都知道,在JDK1.5之前,Java中要进行业务并发时,通常需要有程序员独立完成代码实现,当然也有一些开源的框架提供了这些功能,但是这些依然没有JDK自带的功能使用起来方便。而当针对高质量Java多线程并发程序设计时,为防止死蹦等现象的出现,比如使用java之前的wait()、notify()和synchronized等,每每需要考虑性能、死锁、公平性、资源管理以及如何避免线程安全性方面带来的...

AI技术改变世界 2万+

【软件逆向】带壳带反调试找flag教程(VMProtect3.0+X64dbg+ScyllaHide)

【软件逆向】带壳带反调试找flag教程(VMProtect 3.0+X64dbg+ScyllaHide)

zhangjiuding的博客 7516

基于高光谱的物质反演与分类 — 技术文章(原理详解 + 深度代码实现)

高光谱遥感 / 近场光谱采集产生逐像素上百波段的光谱曲线,是物质识别与定量反演(abundance / composition estimation)和语义分类(landcover / material class)的一把利器。本文第一部分对常用模型(线性混合模型、非线性辐射传输、稀疏反演、降维与特征选择、分类器/神经网络)进行数学推导与理论分析;第二部分给出两套完整实现:A. 基于 LMM 的约束最小二乘 / 稀疏反演流水线(含端到端评估);

VectorShift的博客 221

java concurrent 包_java的concurrent包简介

java的concurrent包简介java的concurrent包中的锁lock;工具类:CyclicBarrier、semaphore、CountDownLatch;集合:blockingquue、concurrentMap;原子量:aotmic。先从下面的图开始,介绍下concurrent包的用法。 1、lock类总结几点现在知道的synchronized的异同,基本也就是个认知阶段,并不能...

weixin_29463587的博客 793

YOLOv12改进策略【Head】| ASFF 自适应空间特征融合模块,改进检测头Detect_ASFF

在目标检测中,处理多尺度物体是一个具有挑战性的问题。虽然特征金字塔或多级特征塔是解决多尺度问题的常用方法,但在单阶段检测器中,不同尺度特征之间的不一致性限制了其性能提升。为了解决这个问题,提出了自适应空间特征融合(ASFF)模块。

Limiiiing的博客 1173

Java中的concurrent包

concurrent包是在JDK1.5时加入的,常说的concurrent包主要由三个package组成 java.util.concurrent:提供大部分关于并发的接口和类,如BlockingQueue,Callable,ConcurrentHashMap,ExecutorService,Semaphore等。 java.util.concurrent.atomic:提供所有原子操作的类,...

刚学会HelloWorld的XXX的博客 781

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

java中concurrent包_java的concurrent包

最近在网上看到一个将concurrent包的系列文章,仔细读了一遍,感觉不错。Concurrent包主要有三个package组成。java.util.concurrent:提供大部分关于并发的接口和类,如BlockingQueue,Callable,ConcurrentHashMap,ExecutorService, Semaphore等。java.util.concurrent.atomic:提...

weixin_34966742的博客 447

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

java concurrent 包_java.util.concurrent包的拆解

java.util.concurrent包:1.locks部分:显式锁(互斥锁和速写锁)相关2.atomic部分:原子变量类相关,是构建非阻塞算法的基础3.executor部分:线程池相关4.collection部分:并发容器相关5.tools部分:同步工具相关,如信号量、闭锁、栅栏等功能1.collection部分:1.1 BlockingQueueBlockingQueue为接口,如果要用它,...

weixin_32001191的博客 85

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

java.util.concurrent介绍

java.util.concurrent 包含许多线程安全、测试良好、高性能的并发构建块。不客气地说,创建 java.util.concurrent 的目的就是要实现 Collection 框架对数据结构所执行的并发操作。通过提供一组可靠的、高性能并发构建块,开发人员可以提高并发类的线程安全、可伸缩性、性能、可读性和可靠性。 如果一些类名看起来相似,可能是因为 java.util.concurrent 中的许多概念源自 Doug Lea 的 util.concurrent 库。 JDK 5.0 中的并发改进

weixin_53341657的博客 3917

java的concurrent包详解

1、 Java 并发工具包 java.util.concurrent 用户指南 2、 java.util.concurrent包学习(一)锁的基本原理 3、Java的synchronized原理 4、http://www.cnblogs.com/onlywujun/articles/3530984.html 5、java.util.concurrent包(1)——lock和sync

帅性而为1号的博客 1803

java concurrent 源码_java 并发(concurrent)包源码分析

参考连接:持续更新中。。。。。并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力。如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善。现代的PC都有多个CPU或一个CPU中有多个核,是否能合理运用多核的能力将成为一个大规模应用程序的关键。Java多线程相关类的实现都在Java的并发包concurrent,concurrent包主要包含3部分内容,...

weixin_30306285的博客 303

java的concurrent/java.util.concurrent.locks用法详解

java.util.concurrent.locks - 内容部份 Lock 接口支持那些语义不同(重入、公平等)的锁定规则 ,可以在非阻塞式结构的上下文(包括 hand-over-hand 和锁定重排算法)中使用这些规则。主要的实现是 ReentrantLock。 ReadWriteLock 接口以类似方式定义了一些读取者可以共享而写入者独占的锁定 。此包只...

muyoufang001 188

java concurrent 锁_Java并发编程:Concurrent锁机制解析

Java并发编程:Concurrent锁机制解析前面,我们讲了Java自带的对象锁机制。因为我们的方法必然是在一个对象中的,所以,通过对象的锁,可以很好的控制对方法的调用。当对象的锁被一个线程持有后,其他线程想要调用该对象的该方法,就必须进入等待池,等待当前线程执行完毕后,由系统来决定选中谁接下来继续执行。这种方法非常的直观,原理也非常的清晰。那么,Doug Lea为什么会额外再开发一个并行包呢?...

weixin_39934257的博客 265
上一篇: 线程池相关
下一篇: linux mysql
zljjava
博客等级 码龄15年 155粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值