赞
踩
多线程并发保证线程的顺序执行
考虑为什么在并发的情况下要保证线程的并发执行
考虑到可能有如下几种情况
1.单纯面试 现场顺序执行的考点就是线程间的通信问题
2.真正的业务需求,如解析XML 我们想并发执行xml下多个节点,但是我们需要解析完成后再继续下不操作,如果节点中有依赖关系那我们就必须要保证一些顺序执行。
一.单纯面试来说 可实现的方式
1.join关键字
关键代码
Thread t3 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"==开始执行");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"==结束执行");
},"t3");
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
System.out.println("所有线程到此执行完毕");
输出结果
t1==开始执行
t1==结束执行
t2==开始执行
t2==结束执行
t3==开始执行
t3==结束执行
所有线程到此执行完毕
为什么join关键字能保证线程顺序执行那
我们看join方法的简介
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
关键代码
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
会发现如果这个线程是活着的话会用while循环阻塞 主线程的运行,来次达到线程顺序执行
2.Executor.newSimpleThreadPool
关键代码
Thread t3 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"=t3=开始执行");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"=t3=结束执行");
},"t3");
ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(t1);
es.execute(t2);
es.execute(t3);
if(es.isShutdown())
es.shutdown();
System.out.println("所有线程到此执行完毕");
执行结果
所有线程到此执行完毕
pool-1-thread-1=t1=开始执行
pool-1-thread-1=t1=结束执行
pool-1-thread-1=t2=开始执行
pool-1-thread-1=t2=结束执行
pool-1-thread-1=t3=开始执行
pool-1-thread-1=t3=结束执行
可以看到 用SimlpPool的话 能保证线程顺序执行,且不阻塞主线程运行
我们可以看SimlpPool 方线程的是LinkedBlockingQueue 链表阻塞队列且容量只为1,而链表是阻塞所有保证线程先进先出的规则来执行
3.Lock下conditional
volatile static int num = 1;
Lock lock = new ReentrantLock();
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
Condition c3 = lock.newCondition();
Thread t1 = new Thread(()->{
lock.lock();
try {
while(num!=1) {
c1.await();
}
System.out.println(Thread.currentThread().getName()+"==开始执行");
TimeUnit.SECONDS.sleep(1);
num = 2;
c2.signal();
System.out.println(Thread.currentThread().getName()+"==结束执行");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
},"t1");
利用lock Condition num 阻塞的方式 实现 线程大顺序执行
我们看下Condition 说明
* <p>Before waiting on the condition the lock must be held by the
* current thread.
* A call to {@link Condition#await()} will atomically release the lock
* before waiting and re-acquire the lock before the wait returns.
在等待条件之前,锁由当前线程持有。调用wait()在等待和重新获得锁之前自动释放锁。
二 对于业务中我们可以考虑Callable接口
public static void test4() throws InterruptedException, ExecutionException {
Future<String> futA = new FutureTask<String>(new Sub1("A", null));
Thread t1 = new Thread((Runnable) futA);
t1.start();
System.out.println(futA.get());
Future<String> futB = new FutureTask<String>(new Sub1("B", null));
Thread t2 = new Thread((Runnable) futB);
t2.start();
System.out.println(futB.get());
Future<String> futC = new FutureTask<String>(new Sub1("C", null));
Thread t3 = new Thread((Runnable) futC);
t3.start();
System.out.println(futC.get());
System.out.println("程序结束");
}
}
class Sub1 implements Callable<String> {
private String str ;
private Map<String, String> map ;
public Sub1() {};
public Sub1(String str,Map<String, String> map) {
this.str = str;
this.map = map ;
};
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。