关于java多线程通信(一)

一、Thread.join()

    若一个线程A执行了thread.join()语句,含义为:线程A需要等待thread线程终止//销毁之后才会从join()方法返回。

    方法:

    join();

    join(long millis);

    join(long millis, int nanos);

   如,两个线程顺序执行,有两个线程A、B,线程B需要在线程A打印完毕后才执行打印操作:

private static void printInOrder() {
	Thread A = new Thread(new Runnable() {
		@Override
		public void run() {
		     printData("A");//打印A线程数据
		}
	});

	Thread B = new Thread(new Runnable() {
		@Override
		public void run() {
			System.out.println("B开始等待A");
			try {
				A.join(); //线程A执行结束,线程B从join()方法返回
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			printData("B");//打印B线程数据
		}
	});
	B.start();
	A.start();
}

上述代码会先打印线程A数据,待线程A执行结束,再打印线程B数据。

这里其实涉及到等待/通知机制(等待前驱线程结束,接收前驱线程的结束通知),具体可查看Thread.join()方法源码。

二、等待/通知机制

1、等待/通知方法是任意java对象都具备的,这些方法都定义在所有对象的超类Object上,如下:

notify();

notifyAll();

wait();

wait(long);

wait(long, int);

线程A调用了对象O的wait()方法,线程B调用了对象O的notify()或notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续的操作。两个线程通过对象O完成交互,对象O上的wait()和notify()就像开关一样,用来完成等待方和通知方之间的交互工作。

使用wait()/notify()时需要先对调用对象加锁。

调用了wait()方法之后,线程状态从runnable变为waiting,并将当前线程放在对象的等待队列中。

调用了notify()方法之后,等待线程不会从wait()返回,需要调用notify()的线程释放锁之后,等待线程才有机会从wait()返回。从wait()方法返回的前提是等待线程获得了调用对象的锁。

如,两个线程有序交叉执行,线程A和线程B交替打印各自的数据:

private static void printInTurn(){
        int count = 1;
	Object lock = new Object();

	Thread A = new Thread(new Runnable() {
		@Override
		public void run() {
			synchronized (lock) {
			    while(count<=100) {
				try {
					System.out.println("进入线程A,count: "+count);
					lock.notify();
					System.out.println("线程A唤醒lock,线程B在线程A释放锁后从wait()返回. 线程A print count: "+count);
					count++;
					lock.wait();
					System.out.println("线程A等待,share count value is "+count);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			    } 
			}
		}
	});
	
	
	Thread B = new Thread(new Runnable(){
		@Override
		public void run() {
			synchronized (lock) {
			    while(count<=100) {
				try {
					System.out.println("进入线程B, count: "+count);
					lock.notify();
					System.out.println("线程B唤醒lock,线程A在线程B释放锁后从wait()方法返回,线程B print count:"+count);
					count++;
					lock.wait();
					System.out.println("线程B等待,share count value is "+count);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			    }

			}
		}
	});
	
	A.start();
	TimeUnit.SECONDS.sleep(10);
	B.start();
}

上述代码会依次交替打印100以内的奇偶数,其中线程A打印奇数,线程B打印偶数。

三、java中的并发工具类

java并发包中的并发工具类有CountDownLatch、CyclicBarrier、Semaphore。

1、CountDownLatch允许一个或多个线程等待其他线程执行完操作。

CountDownLatch构造函数传入一个int型参数N,表示需要等待N个点完成,这里N个点可以表示N个线程,也可以表示1个线程里的N个步骤。执行countDown(),N会减1;await()方法会阻塞当前线程,直到N变为0。另外,如果某个线程处理较慢,不能让等待线程一直等待,使用await(long time, TimeUnit unit),表示在等待特定时间后,就不会阻塞当前线程。

如,线程D需要等待线程A,B,C同步执行完毕后再执行:

private static void countDownLatchTest(){
	CountDownLatch countDownLatch = new CountDownLatch(3);
	
	Thread D = new Thread(new Runnable(){
		@Override
		public void run() {
			System.out.println("线程D等待其他三个线程");
			try {
				countDownLatch.await();
				System.out.println("其他三个线程执行完毕,D开始执行");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	});
	D.start();
	
	for(char name='A';name<='C';name++){
		final String n = String.valueOf(threadName);
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("执行线程:"+n);
				countDownLatch.countDown();
			}
		}).start();
	}
}

2、CyclicBarrier

让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

比如,三个线程A,B,C,都需要做一些准备工作,待这三个线程都准备完毕后,它们才会在同一时间继续执行:

private static void CyclicBarrierTest() {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
    for (char name='A'; name<= 'C'; name++) {
        final String n= String.valueOf(name);
        new Thread(new Runnable() {
            @Override
            public void run() {
                int prepareTime = (int)(Math.random()*1000);
                System.out.println(n+ " prepare time:" + prepareTime);
                try {
                    Thread.sleep(prepareTime);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    System.out.println(n+ " is prepared, waiting for others");
                    cyclicBarrier.await(); //当前线程准备完毕,等待其他线程准备完成
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(n+ " starts running"); //所有线程准备完成,这些线程开始同时执行
            }
        }).start();
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值