Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore

2023-11-18

Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore

2016/10/07 | 分类: 基础技术 | 7 条评论 | 标签: 并发

分享到: 0
原文出处:  海子

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法。

以下是本文目录大纲:

一.CountDownLatch用法

二.CyclicBarrier用法

三.Semaphore用法

一.CountDownLatch用法

CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

CountDownLatch类只提供了一个构造器:

1
public CountDownLatch( int count) {  };  //参数count为计数值

然后下面这3个方法是CountDownLatch类中最重要的方法:

1
2
3
public void await() throws InterruptedException { };   //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await( long timeout, TimeUnit unit) throws InterruptedException { };  //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { };  //将count值减1

下面看一个例子大家就清楚CountDownLatch的用法了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Test {
      public static void main(String[] args) {  
          final CountDownLatch latch = new CountDownLatch( 2 );
 
          new Thread(){
              public void run() {
                  try {
                      System.out.println( "子线程" +Thread.currentThread().getName()+ "正在执行" );
                     Thread.sleep( 3000 );
                     System.out.println( "子线程" +Thread.currentThread().getName()+ "执行完毕" );
                     latch.countDown();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
              };
          }.start();
 
          new Thread(){
              public void run() {
                  try {
                      System.out.println( "子线程" +Thread.currentThread().getName()+ "正在执行" );
                      Thread.sleep( 3000 );
                      System.out.println( "子线程" +Thread.currentThread().getName()+ "执行完毕" );
                      latch.countDown();
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
              };
          }.start();
 
          try {
              System.out.println( "等待2个子线程执行完毕..." );
             latch.await();
             System.out.println( "2个子线程已经执行完毕" );
             System.out.println( "继续执行主线程" );
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
      }
}

执行结果:

1
2
3
4
5
6
7
线程Thread- 0 正在执行
线程Thread- 1 正在执行
等待 2 个子线程执行完毕...
线程Thread- 0 执行完毕
线程Thread- 1 执行完毕
2 个子线程已经执行完毕
继续执行主线程

二.CyclicBarrier用法

字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

CyclicBarrier类位于java.util.concurrent包下,CyclicBarrier提供2个构造器:

1
2
3
4
5
public CyclicBarrier( int parties, Runnable barrierAction) {
}
 
public CyclicBarrier( int parties) {
}

参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。

然后CyclicBarrier中最重要的方法就是await方法,它有2个重载版本:

1
2
public int await() throws InterruptedException, BrokenBarrierException { };
public int await( long timeout, TimeUnit unit) throws InterruptedException,BrokenBarrierException,TimeoutException { };

第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;

第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。

下面举几个例子就明白了:

假若有若干个线程都要进行写数据操作,并且只有所有线程都完成写数据操作之后,这些线程才能继续做后面的事情,此时就可以利用CyclicBarrier了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Test {
     public static void main(String[] args) {
         int N = 4 ;
         CyclicBarrier barrier  = new CyclicBarrier(N);
         for ( int i= 0 ;i<N;i++)
             new Writer(barrier).start();
     }
     static class Writer extends Thread{
         private CyclicBarrier cyclicBarrier;
         public Writer(CyclicBarrier cyclicBarrier) {
             this .cyclicBarrier = cyclicBarrier;
         }
 
         @Override
         public void run() {
             System.out.println( "线程" +Thread.currentThread().getName()+ "正在写入数据..." );
             try {
                 Thread.sleep( 5000 );      //以睡眠来模拟写入数据操作
                 System.out.println( "线程" +Thread.currentThread().getName()+ "写入数据完毕,等待其他线程写入完毕" );
                 cyclicBarrier.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } catch (BrokenBarrierException e){
                 e.printStackTrace();
             }
             System.out.println( "所有线程写入完毕,继续处理其他任务..." );
         }
     }
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
线程Thread- 0 正在写入数据...
线程Thread- 3 正在写入数据...
线程Thread- 2 正在写入数据...
线程Thread- 1 正在写入数据...
线程Thread- 2 写入数据完毕,等待其他线程写入完毕
线程Thread- 0 写入数据完毕,等待其他线程写入完毕
线程Thread- 3 写入数据完毕,等待其他线程写入完毕
线程Thread- 1 写入数据完毕,等待其他线程写入完毕
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...

从上面输出结果可以看出,每个写入线程执行完写数据操作之后,就在等待其他线程写入操作完毕。

当所有线程线程写入操作完毕之后,所有线程就继续进行后续的操作了。

如果说想在所有线程写入操作完之后,进行额外的其他操作可以为CyclicBarrier提供Runnable参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Test {
     public static void main(String[] args) {
         int N = 4 ;
         CyclicBarrier barrier  = new CyclicBarrier(N, new Runnable() {
             @Override
             public void run() {
                 System.out.println( "当前线程" +Thread.currentThread().getName());  
             }
         });
 
         for ( int i= 0 ;i<N;i++)
             new Writer(barrier).start();
     }
     static class Writer extends Thread{
         private CyclicBarrier cyclicBarrier;
         public Writer(CyclicBarrier cyclicBarrier) {
             this .cyclicBarrier = cyclicBarrier;
         }
 
         @Override
         public void run() {
             System.out.println( "线程" +Thread.currentThread().getName()+ "正在写入数据..." );
             try {
                 Thread.sleep( 5000 );      //以睡眠来模拟写入数据操作
                 System.out.println( "线程" +Thread.currentThread().getName()+ "写入数据完毕,等待其他线程写入完毕" );
                 cyclicBarrier.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } catch (BrokenBarrierException e){
                 e.printStackTrace();
             }
             System.out.println( "所有线程写入完毕,继续处理其他任务..." );
         }
     }
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
线程Thread- 0 正在写入数据...
线程Thread- 1 正在写入数据...
线程Thread- 2 正在写入数据...
线程Thread- 3 正在写入数据...
线程Thread- 0 写入数据完毕,等待其他线程写入完毕
线程Thread- 1 写入数据完毕,等待其他线程写入完毕
线程Thread- 2 写入数据完毕,等待其他线程写入完毕
线程Thread- 3 写入数据完毕,等待其他线程写入完毕
当前线程Thread- 3
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...
所有线程写入完毕,继续处理其他任务...

从结果可以看出,当四个线程都到达barrier状态后,会从四个线程中选择一个线程去执行Runnable。

下面看一下为await指定时间的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Test {
     public static void main(String[] args) {
         int N = 4 ;
         CyclicBarrier barrier  = new CyclicBarrier(N);
 
         for ( int i= 0 ;i<N;i++) {
             if (i<N- 1 )
                 new Writer(barrier).start();
             else {
                 try {
                     Thread.sleep( 5000 );
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 new Writer(barrier).start();
             }
         }
     }
     static class Writer extends Thread{
         private CyclicBarrier cyclicBarrier;
         public Writer(CyclicBarrier cyclicBarrier) {
             this .cyclicBarrier = cyclicBarrier;
         }
 
         @Override
         public void run() {
             System.out.println( "线程" +Thread.currentThread().getName()+ "正在写入数据..." );
             try {
                 Thread.sleep( 5000 );      //以睡眠来模拟写入数据操作
                 System.out.println( "线程" +Thread.currentThread().getName()+ "写入数据完毕,等待其他线程写入完毕" );
                 try {
                     cyclicBarrier.await( 2000 , TimeUnit.MILLISECONDS);
                 } catch (TimeoutException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } catch (BrokenBarrierException e){
                 e.printStackTrace();
             }
             System.out.println(Thread.currentThread().getName()+ "所有线程写入完毕,继续处理其他任务..." );
         }
     }
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
线程Thread- 0 正在写入数据...
线程Thread- 2 正在写入数据...
线程Thread- 1 正在写入数据...
线程Thread- 2 写入数据完毕,等待其他线程写入完毕
线程Thread- 0 写入数据完毕,等待其他线程写入完毕
线程Thread- 1 写入数据完毕,等待其他线程写入完毕
线程Thread- 3 正在写入数据...
java.util.concurrent.TimeoutException
Thread- 1 所有线程写入完毕,继续处理其他任务...
Thread- 0 所有线程写入完毕,继续处理其他任务...
     at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
     at java.util.concurrent.CyclicBarrier.await(Unknown Source)
     at com.cxh.test1.Test$Writer.run(Test.java: 58 )
java.util.concurrent.BrokenBarrierException
     at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
     at java.util.concurrent.CyclicBarrier.await(Unknown Source)
     at com.cxh.test1.Test$Writer.run(Test.java: 58 )
java.util.concurrent.BrokenBarrierException
     at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
     at java.util.concurrent.CyclicBarrier.await(Unknown Source)
     at com.cxh.test1.Test$Writer.run(Test.java: 58 )
Thread- 2 所有线程写入完毕,继续处理其他任务...
java.util.concurrent.BrokenBarrierException
线程Thread- 3 写入数据完毕,等待其他线程写入完毕
     at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
     at java.util.concurrent.CyclicBarrier.await(Unknown Source)
     at com.cxh.test1.Test$Writer.run(Test.java: 58 )
Thread- 3 所有线程写入完毕,继续处理其他任务...

上面的代码在main方法的for循环中,故意让最后一个线程启动延迟,因为在前面三个线程都达到barrier之后,等待了指定的时间发现第四个线程还没有达到barrier,就抛出异常并继续执行后面的任务。

另外CyclicBarrier是可以重用的,看下面这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Test {
     public static void main(String[] args) {
         int N = 4 ;
         CyclicBarrier barrier  = new CyclicBarrier(N);
 
         for ( int i= 0 ;i<N;i++) {
             new Writer(barrier).start();
         }
 
         try {
             Thread.sleep( 25000 );
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
 
         System.out.println( "CyclicBarrier重用" );
 
         for ( int i= 0 ;i<N;i++) {
             new Writer(barrier).start();
         }
     }
     static class Writer extends Thread{
         private CyclicBarrier cyclicBarrier;
         public Writer(CyclicBarrier cyclicBarrier) {
             this .cyclicBarrier = cyclicBarrier;
         }
 
         @Override
         public void run() {
             System.out.println( "线程" +Thread.currentThread().getName()+ "正在写入数据..." );
             try {
                 Thread.sleep( 5000 );      //以睡眠来模拟写入数据操作
                 System.out.println( "线程" +Thread.currentThread().getName()+ "写入数据完毕,等待其他线程写入完毕" );
 
                 cyclicBarrier.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } catch (BrokenBarrierException e){
                 e.printStackTrace();
             }
             System.out.println(Thread.currentThread().getName()+ "所有线程写入完毕,继续处理其他任务..." );
         }
     }
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
线程Thread- 0 正在写入数据...
线程Thread- 1 正在写入数据...
线程Thread- 3 正在写入数据...
线程Thread- 2 正在写入数据...
线程Thread- 1 写入数据完毕,等待其他线程写入完毕
线程Thread- 3 写入数据完毕,等待其他线程写入完毕
线程Thread- 2 写入数据完毕,等待其他线程写入完毕
线程Thread- 0 写入数据完毕,等待其他线程写入完毕
Thread- 0 所有线程写入完毕,继续处理其他任务...
Thread- 3 所有线程写入完毕,继续处理其他任务...
Thread- 1 所有线程写入完毕,继续处理其他任务...
Thread- 2 所有线程写入完毕,继续处理其他任务...
CyclicBarrier重用
线程Thread- 4 正在写入数据...
线程Thread- 5 正在写入数据...
线程Thread- 6 正在写入数据...
线程Thread- 7 正在写入数据...
线程Thread- 7 写入数据完毕,等待其他线程写入完毕
线程Thread- 5 写入数据完毕,等待其他线程写入完毕
线程Thread- 6 写入数据完毕,等待其他线程写入完毕
线程Thread- 4 写入数据完毕,等待其他线程写入完毕
Thread- 4 所有线程写入完毕,继续处理其他任务...
Thread- 5 所有线程写入完毕,继续处理其他任务...
Thread- 6 所有线程写入完毕,继续处理其他任务...
Thread- 7 所有线程写入完毕,继续处理其他任务...

从执行结果可以看出,在初次的4个线程越过barrier状态后,又可以用来进行新一轮的使用。而CountDownLatch无法进行重复使用。

三.Semaphore用法

Semaphore翻译成字面意思为 信号量,Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

Semaphore类位于java.util.concurrent包下,它提供了2个构造器:

1
2
3
4
5
6
public Semaphore( int permits) {          //参数permits表示许可数目,即同时可以允许多少线程进行访问
     sync = new NonfairSync(permits);
}
public Semaphore( int permits, boolean fair) {    //这个多了一个参数fair表示是否是公平的,即等待时间越久的越先获取许可
     sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
}

下面说一下Semaphore类中比较重要的几个方法,首先是acquire()、release()方法:

1
2
3
4
public void acquire() throws InterruptedException {  }     //获取一个许可
public void acquire( int permits) throws InterruptedException { }    //获取permits个许可
public void release() { }          //释放一个许可
public void release( int permits) { }    //释放permits个许可

acquire()用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许可。

release()用来释放许可。注意,在释放许可之前,必须先获获得许可。

这4个方法都会被阻塞,如果想立即得到执行结果,可以使用下面几个方法:

1
2
3
4
public boolean tryAcquire() { };    //尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire( long timeout, TimeUnit unit) throws InterruptedException { };  //尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
public boolean tryAcquire( int permits) { }; //尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire( int permits, long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false

另外还可以通过availablePermits()方法得到可用的许可数目。

下面通过一个例子来看一下Semaphore的具体使用:

假若一个工厂有5台机器,但是有8个工人,一台机器同时只能被一个工人使用,只有使用完了,其他工人才能继续使用。那么我们就可以通过Semaphore来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
     public static void main(String[] args) {
         int N = 8 ;            //工人数
         Semaphore semaphore = new Semaphore( 5 ); //机器数目
         for ( int i= 0 ;i<N;i++)
             new Worker(i,semaphore).start();
     }
 
     static class Worker extends Thread{
         private int num;
         private Semaphore semaphore;
         public Worker( int num,Semaphore semaphore){
             this .num = num;
             this .semaphore = semaphore;
         }
 
         @Override
         public void run() {
             try {
                 semaphore.acquire();
                 System.out.println( "工人" + this .num+ "占用一个机器在生产..." );
                 Thread.sleep( 2000 );
                 System.out.println( "工人" + this .num+ "释放出机器" );
                 semaphore.release();          
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
}

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
工人 0 占用一个机器在生产...
工人 1 占用一个机器在生产...
工人 2 占用一个机器在生产...
工人 4 占用一个机器在生产...
工人 5 占用一个机器在生产...
工人 0 释放出机器
工人 2 释放出机器
工人 3 占用一个机器在生产...
工人 7 占用一个机器在生产...
工人 4 释放出机器
工人 5 释放出机器
工人 1 释放出机器
工人 6 占用一个机器在生产...
工人 3 释放出机器
工人 7 释放出机器
工人 6 释放出机器

下面对上面说的三个辅助类进行一个总结:

1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

参考资料:

Java编程思想

http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html

http://leaver.me/archives/3220.html

http://developer.51cto.com/art/201403/432095.htm

http://blog.csdn.net/yanhandle/article/details/9016329

http://blog.csdn.net/cutesource/article/details/5780740

http://www.cnblogs.com/whgw/archive/2011/09/29/2195555.html




http://www.importnew.com/21889.html


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore 的相关文章

  • std::atomic_thread_fence

    在原子变量的存取上应用不同的memory order可以实现不同的内存序来达到数据同步的目的 xff0c 而在C 43 43 11及之后的标准里 xff0c 除了利用原子操作指定内存序 xff0c 还定义了单独使用 内存栅栏 xff08 s
  • ORA-00322, ORA-00312 问题解决

    昨天发现无法登录Oracle数据库 通过sqlplus工具open数据库时报如下错误 alter database open ERROR at line 1 ORA 00322 log 2 of thread 1 is not curren
  • Python使用threading.Timer实现执行可循环的定时任务

    前言 Python中使用threading Timer执行定时任务时 执行任务是一次性的 类似于JS中的setTimeout方法 我们对其在封装 改造成可循环的定时器 类似于JS中setInterval方法的效果 值得注意的是 thread
  • yield和join方法的使用。

    join方法用线程对象调用 如果在一个线程A中调用另一个线程B的join方法 线程A将会等待线程B执行完毕后再执行 yield可以直接用Thread类调用 yield让出CPU执行权给同等级的线程 如果没有相同级别的线程在等待CPU的执行权
  • AFX_MANAGE_STATE(AfxGetStaticModuleState())讲解

    以前写MFC的DLL的时候 总会在自动生成的代码框架里看到提示 需要在每一个输出的函数开始添加上AFX MANAGE STATE AfxGetStaticModuleState 一直不明白这样做的含义 也一直没有这样做 而且代码也工作得好好
  • 代码潜在故障的动态分析

    b size large 引子 size b 大家都听说过FindBugs的大名 这是一款静态代码分析的工具 能够直接对字节码文件加以分析 并发现潜在的反模式 anti pattern 从而有效地促进代码质量的改善 但FindBugs只能用
  • C#-Async关键字(异步方法)

    async关键字 异步方法 async关键字是C 特有的 Java没有这玩意 async在C 世界里是上下文关键字 它只有在修饰一个方法的时候才自动被编译器识别为关键字 在代码的其他位置上可以被用作变量名等其他任何用途 async关键字用来
  • Java 多线程 -- 从入门到精通

    持续更新中 欢迎收藏 关注 以便查看后续 Java 多线程 从入门到精通 Java线程与线程的区别 多线程的实现方法 Thread中start和run方法的区别 Thread和Runnable的关系 使用Callable和Future创建线
  • java多线程实战( 多个线程 修改同一个变量)

    java多线程实战 多个线程 修改同一个变量 synchronized 同步 介绍 java多线程实战 需求 创建两个线程 分别输出 a b 要求输出总和为30个 线程介绍 一 定义线程 1 扩展java lang Thread类 此类中有
  • java多线程使用详解与案例,超详细

    文章目录 线程lamda表达式方式启动 简单 常用 java使用多线程的三种方式 继承Thread 实现Runnable 实现Callable 线程池的使用 守护线程 使用lamda表达式简化java的书写简单化案例如下 多线程综合案例 1
  • Java--多线程(2)---yield

    yield yield 在Java的多线程中指的是礼让的意思 具体作用就是 停止当前正在执行的线程对象 去执行其他的线程 yield作用与相同优先级之间的线程 目的是让相同优先级的线程可以交替进行 yield有时也可能不会执行 举例 pub
  • 【最清晰】ThreadLocal和局部变量和成员变量的区别

    ThreadLocal是进程级别的全局变量 最近有一个疑惑 为什么线程类的局部变量不能完全替代ThreadLocal 每一次new 线程都是创建了一个副本啊照理来说也是独立的 为什么还需要ThreadLocal 实际上确实是独立的 但是答案
  • JSVC简介之快速入门

    1 JSVC简介 Apache基金会会common 类似于guava 项目下的项目 2 为什么要使用JSVC java应用增加一种启动方式 Java的缺点 只能用main方法启动 应用能使用1024以下端口 为啥tomcat可以指定端口 系
  • 分析Java线程池执行原理

    Java并发编程源码分析系列 分析Java线程池的创建 上一篇已经对线程池的创建进行了分析 了解线程池既有预设的模板 也提供多种参数支撑灵活的定制 本文将会围绕线程池的生命周期 分析线程池执行任务的过程 线程池状态 首先认识两个贯穿线程池代
  • VC 如何使程序运行后自己删除自己

    VC 如何使程序运行后自己删除自己 有时候 我们需要创建一个运行后能够自己删除自己的可执行程序即自删除程序 很明显如果一个进程通过直接调用DeleteFile 来删除自己是不可能的 必须另想办法 经过本人在网上参考很多资料后实际测试并集众家
  • 使用org.apache.tools.zip包操作文件

    import java io import org apache tools zip import java util Enumeration 功能 zip压缩 解压 支持中文文件名 说明 本程序通过使用Apache Ant里提供的zip工
  • C++11多线程std::thread的简单使用

    文章转载自http blog csdn net star530 article details 24186783 在cocos2dx 2 0时代 我们使用的是pthread库 是一套用户级线程库 被广泛地使用在跨平台应用上 但在cocos2
  • Java-多线程-给线程命名

    Java 多线程 给线程命名 在Java中 通过继承Thread创建的线程 有以下两种方式可以给线程命名 通过构造器命名 因为线程类继承自Thread类 所有也继承了Thread的name属性 可以通过super的方法调用父类构造器 将na
  • python基于字典多线程目录枚举工具

    基于字典多线程目录枚举工具 整体思路 命令行参数获取 字典文件的读取 多线程访问 命令行参数获得 使用模块 sys getopt sys argv获取命令行执行的数据 参数获得 opt args getopt getopt sys argv
  • 一、使用interrupt()中断线程

    当一个线程运行时 另一个线程可以调用对应的Thread对象的interrupt 方法来中断它 该方法只是在目标线程中设置一个标志 表示它已经被中断 并立即返回 这里需要注意的是 如果只是单纯的调用interrupt 方法 线程并没有实际被中

随机推荐

  • CS224W 第一讲 图论基本知识回顾

    网络的组成 一个网络由 对象 关系 系统 组成 网络的表示 有向图和无向图 节点的度 这里平均度数分别为 2E N 和 E N 同时 有向图有一个很重要的概念就是 所有的出度和入度是相同的 完全图 clique or Complete gr
  • 前端传递base64编码,java后端接收,并转为MultipartFile对象

    前端传递的base64 通过url Base64中的 和 字符变为形如 XX 的形式 所以后端接收的字符串是带 的 所以需要解码 String decode URLDecoder decode avatar 下面是工具类 base64转为m
  • 3DMax 卡死、白屏、渲染死机问题总结

    白屏 3dmax出现白屏解决方法 以下是ChatGPT给出的答案 内存不足 3DsMax需要大量的内存才能正常运行 如果你的计算机内存不足 3DsMax就会卡死 解决办法是升级你的计算机内存或者关闭一些不必要的程序来释放内存 显卡驱动过时
  • C++之tuple

    2023年6月4日 周日下午 今天下午简单学习了一下tuple 现在来简单介绍一下tuple 功能 生成一个含不同数据类型的元素列 创建 可以通过声明或make tuple来创建tuple include
  • 在Qt中,如何布局,让控件显示在自己想要的位置

    想到一个办法 可以使用QGridLayout 使用空的QLabel填充空白位置 空的QLabel是透明的 所以看起来就是被填充区域为空白 可以让自己想要显示的控件显示在右上方或者左下方或者任何想要显示的地方 绿色为填充的空QLabel 如图
  • 网课重学宣言:御风计划

    当前状态 我报了网课 2023年4月份报的花了1w3 现在是快7月份了 但是我没学多少 这一份课程的学习困难重重 如今我面临两个选择 一个是放弃这么课 跟着流程继续学习 能学一点是一点 然后把其他精力放在别的方面 另一个是重新延期学习 重新
  • Qt下监测内存泄漏

    在写Qt应用程序时 由于是采用C 语言 经常会碰到一个令人棘手的问题 那就是内存泄漏 虽然后面C 为了防止内存泄漏 发布了智能指针以用来避免内存泄漏 但是并不能完全避免 而且智能指针使用不当 同样会造成非常严重的问题 这里智能指针就不在赘述
  • 项目在was 7.0上部署问题解决方案

    年前 在做项目的时候 遇到客户要求应用服务器采用WebSphere服务器 之前从来没有接触过该类服务器 所以项目在架构部署上遇到了很多问题 现在给自己做个笔记 记录一下在websphere应用上遇到的问题 为以后做参考 同时 给有遇到此问题
  • 谈GPT-2(附大量网址)

    文章目录 前言 关于GPT 2 各个版本的GTP 2 中文版GTP 2 语料链接 15亿参数版GPT 2 OpenGPT 2 前言 GPT 2这个名字不知有多少人知道 但有很多人应该都知道埃隆 马斯克的OpenAI吧 OpenAI 由诸多硅
  • Python时间模块之calendar模块

    目录 简介 calendar month isleap calendar leapdays monthcalendar monthrange timegm 总结 简介 在项目开发中做功能经常会用到关于时间的操作 比如会员过期的定时任务 一些
  • 计算机视觉需要学什么?CV知识点

    最近有人问计算机视觉需要学什么 我自己本身是通过自学然后找到了计算机视觉相关的工作 这里我分享一下自己的当初掌握的知识点 希望能帮助到你 以下内容仅供参考 计算机视觉需要学什么 学习计算机视觉需要具备的知识储备有 1 图像处理的知识 图像处
  • 记录一次rabbitmq ConfirmCallback不生效的问题

    记录一次rabbitmq回调函数不生效的问题 application yml里是否存在 springboot版本的问题 改为2 1 7 RELEASE即可 以上都未生效的话 检查一下是否自己写了连接rabbitmq的bean 在里面加上下面
  • Unity 3D中的帧动画播放

    帧动画 Frame By Frame 的原理 链接 项目实例资源 关键是连续的关键帧分解动作 也就是在时间轴的每帧上逐帧绘制不同的内容 使其连续播放而成动画 虽然每一帧都不一样 处理的信息量大 但是 帧动画具有非常大的灵活性 几乎可以表现任
  • C/C++之内存四区

    程序运行时 将内存大致分为四个区域 代码区 存放函数体的二进制代码 由操作系统进行管理的 全局区 存放 全局变量和 静态变量以及 常量 栈区 由编译器自动分配释放 存放函数的参数值 局部变量等 堆区 由程序员分配和释放 若程序员不释放 程序
  • numpy——mgrid

    x1 x2 np mgrid x1min x1max num1j x2min x2max num2j x1返回的是x1min到x1max间均匀分成num1个数 进行横向扩展为方阵 x2返回的是x2min到x2max间均匀分成num2个数 进
  • 企业级数据单表全量增量抽取数据模型(Kettle版)

    最近在使用Kettle进行ETL的工作 现在总结一下 需求是将MYSQL中的表数据增量备份到HIVE仓库中 第一次是全量 我只想给大伙来点实用的 避免大家踩坑 Kettle是一个基于图形化的ETL工具 也可以用于集成各种作业 比如Sqoop
  • Spring Boot之自定义JSON转换器

    JSON是前后端数据交互最流行的格式 在目前的项目开发中 常见的JSON的转换器有三种 json lib由于自身的缺陷基本不用 最广泛的还是Jackson Jackson 在springboot中默认添加了jackson databind作
  • 使用go语言整合gin,驱动bartender打印标签程序

    可以用来当中间件 项目地址 github GitHub wjdsg0327 printer barTender 使用go语言整合gin驱动bartender打印标签 gitee printer barTender 使用go整合gin驱动ba
  • [kubernetes]step3-kubeadm更新证书有效期

    kubeadm更新kubernetes集群证书 接着上面阿里云上的kubernetes集群 一步步搭建服务 因为kubernetes要上云测试了 不想到时候突然因为证书导致服务挂掉 挨批 就把证书更新一下 感觉10年差不多了 查看证书过期时
  • Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore

    Java并发编程 CountDownLatch CyclicBarrier和 Semaphore 2016 10 07 分类 基础技术 7 条评论 标签 并发 分享到 0 原文出处 海子 在java 1 5中 提供了一些非常有用的辅助类来帮