Java Thread中的线程执行控制
Contents
join是Thread对象里的方法.签名如下:
public final void join() throws InterruptedException {
join(0);
}
它的作用是: 当某个Thread调用join方法时,其他线程,必须要等待这个线程(即调用join的线程)运行完毕(正常执行完,或者抛出异常,但它不会影响其他线程正常执行),才能继续执行.
Talk is cheap , show me the code.
public static void main(String[] args) throws InterruptedException {
MyThread t1 = new MyThread();
t1.setName("t1--thread");
t1.start();
t1.join();
MyThread t2 = new MyThread();
t2.setName("t2--thread");
t2.start();
t2.join();
Thread.sleep(1 * 1000);
MyThread t3 = new MyThread();
t3.setName("t3--thread");
t3.start();
t3.join();
}
public static class MyThread extends Thread {
@Override
public void run() {
int i = 5;
while (i-- > 0) {
System.out.println("in thread " + Thread.currentThread().getName());
try {
Thread.sleep(1*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// if( i == 4 && Thread.currentThread().getName().equalsIgnoreCase("t1--thread")){
// throw new RuntimeException("error for t1--thread");
// }
}
}
}
它的执行结果是:
in thread t1--thread
in thread t1--thread
in thread t1--thread
in thread t1--thread
in thread t1--thread
in thread t2--thread
in thread t2--thread
in thread t2--thread
in thread t2--thread
in thread t2--thread
in thread t3--thread
in thread t3--thread
in thread t3--thread
in thread t3--thread
in thread t3--thread
Process finished with exit code 0
如果中间线程出现异常时:
in thread t1--thread
Exception in thread "t1--thread" java.lang.RuntimeException: error for t1--thread
at com.spring.pojo.BasePojo$MyThread.run(BasePojo.java:117)
in thread t2--thread
in thread t2--thread
in thread t2--thread
in thread t2--thread
in thread t2--thread
in thread t3--thread
in thread t3--thread
in thread t3--thread
in thread t3--thread
in thread t3--thread
Process finished with exit code 0
可以看到,第一条线程的异常,并不会影响其他线程的执行.
延伸
CountDownLatch
这个是某条线程,等待 CountDownLatch
计数完毕后才执行.注意,这个计数器是不能重用的.
code:
public static void main(String[] args) throws InterruptedException {
final int COUNT = 3;
CountDownLatch countDownLatch = new CountDownLatch(COUNT);
for(int i=0; i<COUNT; i++){
new MyThread(countDownLatch).start();
}
MyCountDownLatch myCountDownLatch = new MyCountDownLatch(countDownLatch);
myCountDownLatch.start();
}
public static class MyCountDownLatch extends Thread{
CountDownLatch countDownLatch;
public MyCountDownLatch(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
//等待计数器变成0,它会一直阻塞,直到计数器为0
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("wait for other thread finish.");
}
}
public static class MyThread extends Thread {
CountDownLatch countDownLatch;
public MyThread(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
int i = 5;
while (i-- > 0) {
System.out.println("in thread " + Thread.currentThread().getName());
try {
Thread.sleep(1*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//将计数器减1
countDownLatch.countDown();
}
}
执行结果如下:
in thread Thread-0
in thread Thread-1
in thread Thread-2
in thread Thread-0
in thread Thread-1
in thread Thread-2
in thread Thread-0
in thread Thread-1
in thread Thread-2
in thread Thread-0
in thread Thread-1
in thread Thread-2
in thread Thread-0
in thread Thread-1
in thread Thread-2
wait for other thread finish.
Process finished with exit code 0
CyclicBarrier
它是一个可重用的计数器屏障。
它有两个构造函数:
构造函数一
它表示
parties
条线程都到达某个状态时,就执行barrierAction
线程的内容.
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
构造函数二
它表示
parties
条线程都到达某个状态时,什么也不执行(可以看到,调用第一个构造函数,并且第二人Runnable的参数为null)
public CyclicBarrier(int parties) {
this(parties, null);
}
例子
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
final int COUNT = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(COUNT, new Runnable() {
@Override
public void run() {
System.out.println("all done.");
}
});
for (int i = 0; i < COUNT; i++) {
new MyThread(cyclicBarrier).start();
}
}
public static class MyThread extends Thread {
CyclicBarrier cyclicBarrier;
public MyThread(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("in thread " + Thread.currentThread().getName());
try {
int j = new Random().nextInt(10);
System.out.println("thread " + Thread.currentThread().getName() + " sleep " + j + " s");
Thread.sleep(j * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//通知 CyclicBarrier 该线程已经完成(或者说到了状态),等待其他线程到达了这个状态,再继续执行.
System.out.println("thread " + Thread.currentThread().getName() + " done.");
try {
//这个表示无限等待,等其他所有线程都完毕后,才能继续执行下面的.
cyclicBarrier.await();
//,还有个重载方法:它表示通知 CyclicBarrier,它已经到达了某状态,再等1分钟,然后就继续执行下面的方法体了.
//cyclicBarrier.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
执行的结果如下:
in thread Thread-0
in thread Thread-1
thread Thread-0 sleep 8 s
thread Thread-1 sleep 4 s
in thread Thread-2
thread Thread-2 sleep 9 s
thread Thread-1 done.
thread Thread-0 done.
thread Thread-2 done.
all done.
Process finished with exit code 0
可用重例子
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
final int COUNT = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(COUNT, new Runnable() {
@Override
public void run() {
System.out.println("all done.");
}
});
for (int i = 0; i < COUNT; i++) {
new MyThread(cyclicBarrier).start();
}
//让上面的先执行,然后再重用 cyclicBarrier
Thread.sleep(1*1000);
for (int i = 0; i < COUNT; i++) {
new MyThread(cyclicBarrier).start();
}
}
public static class MyThread extends Thread {
CyclicBarrier cyclicBarrier;
public MyThread(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("in thread " + Thread.currentThread().getName());
try {
int j = new Random().nextInt(10);
System.out.println("thread " + Thread.currentThread().getName() + " sleep " + j + " s");
Thread.sleep(j * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//通知 CyclicBarrier 该线程已经完成(或者说到了状态),等待其他线程到达了这个状态,再继续执行.
System.out.println("thread " + Thread.currentThread().getName() + " done.");
try {
//这个表示无限等待,等其他所有线程都完毕后,才能继续执行下面的.
cyclicBarrier.await();
//,还有个重载方法:它表示通知 CyclicBarrier,它已经到达了某状态,再等1分钟,然后就继续执行下面的方法体了.
//cyclicBarrier.await(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
执行结果如下:
in thread Thread-0
in thread Thread-1
in thread Thread-2
thread Thread-0 sleep 4 s
thread Thread-1 sleep 0 s
thread Thread-2 sleep 6 s
thread Thread-1 done.
in thread Thread-3
thread Thread-3 sleep 3 s
in thread Thread-4
thread Thread-4 sleep 0 s
thread Thread-4 done.
in thread Thread-5
thread Thread-5 sleep 6 s
thread Thread-0 done.
all done.
thread Thread-3 done.
thread Thread-2 done.
thread Thread-5 done.
all done.
Process finished with exit code 0
可以看到,CountDownLatch
只保证(执行构造函数里的Runnable线程之前,肯定是有3条线程执行完毕的)。如此循环.
Semaphore
即信号量,通过 acquire() 方法获得使用资源的权限,通过 release() 方法释放资源占用.
例如,网吧只有5台电脑,但有10个人要上网。这样子,我们就可以用Semaphore
来模拟这种情况,代码如下:
public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
//只有 5台电脑
final int COUNT = 5;
final int PERSON = 10;
final Semaphore semaphore = new Semaphore(COUNT, true);
for (int i = 0; i < PERSON; i++) {
new MyThread(semaphore).start();
}
}
public static class MyThread extends Thread {
Semaphore semaphore;
public MyThread(final Semaphore semaphore) {
this.semaphore = semaphore;
}
@Override
public void run() {
try {
semaphore.acquire();
int time = new Random().nextInt(10);
System.out.println("小混混 " + Thread.currentThread().getName() + " 要使用电脑" + time + "小时 正在使用电脑");
Thread.sleep(time * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println("小混混 " + Thread.currentThread().getName() + " 用完了电脑");
}
}
}
执行结果如下:
小混混 Thread-0 要使用电脑1小时 正在使用电脑
小混混 Thread-1 要使用电脑9小时 正在使用电脑
小混混 Thread-2 要使用电脑2小时 正在使用电脑
小混混 Thread-3 要使用电脑6小时 正在使用电脑
小混混 Thread-4 要使用电脑9小时 正在使用电脑
小混混 Thread-0 用完了电脑
小混混 Thread-5 要使用电脑2小时 正在使用电脑
小混混 Thread-2 用完了电脑
小混混 Thread-6 要使用电脑8小时 正在使用电脑
小混混 Thread-5 用完了电脑
小混混 Thread-7 要使用电脑8小时 正在使用电脑
小混混 Thread-3 用完了电脑
小混混 Thread-8 要使用电脑9小时 正在使用电脑
小混混 Thread-1 用完了电脑
小混混 Thread-9 要使用电脑5小时 正在使用电脑
小混混 Thread-4 用完了电脑
小混混 Thread-6 用完了电脑
小混混 Thread-7 用完了电脑
小混混 Thread-9 用完了电脑
小混混 Thread-8 用完了电脑
Process finished with exit code 0