多线程同步

本文深入探讨Java多线程中线程间的通信方法,包括join控制执行顺序、使用wait和notify实现线程同步及交叉执行、利用CountDownLatch确保一组线程完成后再执行特定线程,以及如何通过Callable和FutureTask获取线程处理结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java多线程通信

最近在研究java多线程,这篇文章主要是介绍一些线程之间的通信:

1:join 的方式,一个线程等待另一个线程执行完毕后在执行,可以控制线程执行的顺序;

场景:B线程要在A线程完成后才开始任务:

不做任何控制的情况下的线程代码如下:

复制代码
@Test
    public void threadTest4() throws InterruptedException, ExecutionException {
//        线程A
        final Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                printNum("线程A");
            }
        });
//        线程B
        Thread threadB= new Thread(new Runnable() {
            @Override
            public void run() {
//                try {
//                    threadA.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                printNum("线程B");
            }
        });

        threadA.start();
        threadB.start();
        Thread.sleep(1000);
    }
复制代码
?
1
2
3
4
5
6
7
8
9
10
11
private void printNum(String threadName){
         int i= 0 ;
         while (i++< 3 ){
             try {
                 Thread.sleep( 10 );
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             System.out.println(threadName+ "打印" +i);
         }
     }

这样打印出来的效果如下:

?
1
2
3
4
5
6
线程B打印 1
线程A打印 1
线程B打印 2
线程A打印 2
线程B打印 3
线程A打印 3

这样不能保证 B 线程在A 线程执行完之后再执行;可以通过 join 方法来实现我们的需求: 当在 B 线程调用 A线程的join 方法 则会 B 线程等待A线程执行完了之后再执行B 线程;将上面注掉的代码解开就行了;

这样打印出来的效果是:

?
1
2
3
4
5
6
线程A打印 1
线程A打印 2
线程A打印 3
线程B打印 1
线程B打印 2
线程B打印 3

这样就能保证 B 线程在 A线程执行结束后再执行;

2:多个线程按照一定的顺序交叉执行:

场景:A 线程执行打印完 1 2 后 B 线程再执行打印 1 2 3 

这样的场景需要使用 锁的等待和唤醒的机制来实现,代码实现如下:  需要用到两个方法 wait  和 notify 方法  这两个方法都是 Object对象的方法;

?
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
46
@Test
     public void threadTest5() throws InterruptedException, ExecutionException {
         final Object o= new Object();
         Thread threadA = new Thread( new Runnable() {
             @Override
             public void run() {
                 synchronized (o){
                     System.out.println( "线程A 打印 1" );
                     try {
                         o.wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println( "线程A 打印 2" );
                     System.out.println( "线程A 打印 3" );
                 }
 
             }
         });
 
         Thread threadB = new Thread( new Runnable() {
             @Override
             public void run() {
                 synchronized (o){
                     System.out.println( "线程B 打印 1" );
                     try {
                         Thread.sleep( 100 );
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println( "线程B 打印 2" );
                     try {
                         Thread.sleep( 100 );
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println( "线程B 打印 3" );
                     o.notify();
                 }
 
             }
         });
         threadA.start();
         threadB.start();
         Thread.sleep( 1000 );
     }

下面分析这段代码的执行顺序:

1:创建对象锁 

final Object o=new Object();

2:A 首先获得对象锁的控制权;

3:A 调用  wait 方法 让出对象锁的控制权:

o.wait();

4:B 线程获得对象锁的控制权:

B线程的业务代码处理完之后 调用 notify 方法,唤醒 正在 wait  的线程 然后结束B线程的同步代码块,

5:A 线程获取到了对象锁的控制权后执行自己的业务逻辑;

这样就满足我们需要的场景;

3: 四个线程 A B C D,其中 D 要等到 A B C 全执行完毕后才执行,而且 A B C 是同步运行的

通过 调用对象锁的 notify 和 wait 方法可以满足线程的执行顺序 但是线程是一次执行的,不能同时进行;

需要同步进行有需要进行控制线程的执行顺序则可以使用 线程计数器来实现  

代码如下:

?
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
@Test
     public void threadTest1() throws InterruptedException {
         int worker = 3 ;
         System.out.println( "计数器的值为:" + worker);
         final CountDownLatch countDownLatch = new CountDownLatch(worker);
         Thread threadD = new Thread( new Runnable() {
             @Override
             public void run() {
 
                 System.out.println( "D 线程等待其他线程!" );
                 try {
                     countDownLatch.await();
                     System.out.println( "其他线程运行结束,D线程开始" );
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         });
         threadD.start();
 
         for ( int i = 0 ; i < 3 ; i++) {
 
             final int finalI = i;
             Thread threadA = new Thread( new Runnable() {
                 @Override
                 public void run() {
                     System.out.println(Thread.currentThread().getName() + finalI + "is working" );
                     try {
                         Thread.sleep( 100 );
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println(Thread.currentThread().getName() + finalI + "is finish" );
                     countDownLatch.countDown();
                 }
             });
             threadA.start();
         }
 
         Thread.sleep( 1000 );
 
     }

  上面代码的执行顺序如下:

1:创建线程计数器:计数器的计数个数为3;

2:当D线程开始执行的时候调用计数器的 await 方法,然后等待;

3:执行 ABC 线程的业务逻辑的处理,在线程的业务逻辑处理之后分别调用 计数器的 数字减1.

4:当计数器的数值为0 时D线程获得执行权,开始执行;

 

4:多线程获取线程处理的返回值:

代码如下:

复制代码
@Test
    public void threadTest3() throws InterruptedException, ExecutionException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("开始任务!!");
                Thread.sleep(100);
                int result=0;
                for (int i = 0; i <100 ; i++) {
                    result +=i;
                }
                return result;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
        new Thread(futureTask).start();
        System.out.println("任务获取前");
        System.out.println("任务获取到的结果是:"+futureTask.get());
        System.out.println("任务获取后");
        Thread.sleep(1000);

    }
复制代码

通过Callable  和 FutureTask 两类可以实现这个功能, 注意 FutureTask  的 get()方法是同步,必须在callable中的call 方法执行结束后;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值