线程按照顺序执行实现方式
线程的状态
-
初始(NEW):新建一个新的线程,还未调用start()。
-
运行(RUNNABLE):已经准备就绪和正在运行中的两种状态都称为运行态,准备就绪的线程会放在线程池中等待被调用。
-
阻塞(BLOCKED):某种原因放弃Cpu的使用权,等到线程进入就绪状态才有可能转换为运行态。
-
等待(WAITING):该状态的线程需要等待其他线程中断或者做出通知。
-
超时等待(TIME_WAITING):可以在制定的时间内自行返回。
-
终止(TERMINATED):线程任务执行完毕。
Join实现线程顺序执行
将几个并行的线程合并为一个单线程执行,当一个线程必须等待另一个线程执行完毕后才能执行时,使用Join
public final void join();
public final synchronized void join(long millis);
public final synchronized void join(long millis, int nanos);
- demo
public class ThreadJoinUse {
private static final Logger logger = LoggerFactory.getLogger(ThreadJoinUse.class);
class One extends Thread{
@Override
public void run() {
logger.info("=====》我是One线程");
}
}
class Two extends Thread{
@Override
public void run() {
logger.info("=====》我是Two线程");
}
}
class Three extends Thread{
@Override
public void run() {
logger.info("=====》我是Three线程");
}
}
@Test
public void test1() throws InterruptedException {
Thread thread1 = new Thread(new One());
thread1.start();
thread1.join();
Thread thread2 = new Thread(new Two());
thread2.start();
thread2.join();
Thread thread3 = new Thread(new Three());
thread3.start();
thread3.join();
}
}
创建单一线程池实现顺序执行
创建一个只有一个线程的线程池操作,会创建一个线程队列,按FIFO的顺序执行里面的线程。
- demo
@Test
public void test1(){
ExecutorService executorService = Executors.newSingleThreadExecutor();
Thread one = new One();
Thread two = new Two();
Thread three = new Three();
executorService.submit(one);
executorService.submit(two);
executorService.submit(three);
executorService.shutdown();
}
CountDownLatch(计数器) 实现线程顺序执行
使用juc包下的CountDownLatch实现按序执行线程。
- demo
public class CountDawnLanchUse {
private static final Logger logger = LoggerFactory.getLogger(ThreadJoinUse.class);
class One extends Thread{
int num;
CountDownLatch countDownLatch;
public One(int i, CountDownLatch countDownLatch) {
this.num=i;
this.countDownLatch=countDownLatch;
}
@Override
public void run() {
logger.info("=====》我是One线程");
for (int i = 0; i < num; i++) {
countDownLatch.countDown();
logger.info("=====>线程one的数为:"+String.valueOf(countDownLatch.getCount()));
}
}
}
class Two extends Thread{
int num;
CountDownLatch countDownLatch;
public Two(int i, CountDownLatch countDownLatch) {
this.num=i;
this.countDownLatch=countDownLatch;
}
@Override
public void run() {
logger.info("=====》我是Two线程");
for (int i = 0; i < num; i++) {
countDownLatch.countDown();
logger.info("=====>线程two的数为:"+String.valueOf(countDownLatch.getCount()));
}
}
}
class Three extends Thread{
int num;
CountDownLatch countDownLatch;
public Three(int i, CountDownLatch countDownLatch) {
this.num=i;
this.countDownLatch=countDownLatch;
}
@Override
public void run() {
logger.info("=====》我是Three线程");
for (int i = 0; i < num; i++) {
countDownLatch.countDown();
logger.info("=====>线程three的数为:"+String.valueOf(countDownLatch.getCount()));
}
}
}
@Test
public void test1(){
int numOne = 10;
int numTwo = 20;
int numThree = 30;
CountDownLatch oneCountDownLatch = new CountDownLatch(numOne);
CountDownLatch twoCountDownLatch = new CountDownLatch(numTwo);
CountDownLatch threeCountDownLatch = new CountDownLatch(numThree);
Thread one = new One(numOne,oneCountDownLatch);
one.start();
try {
oneCountDownLatch.await();
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
Thread two = new Two(numTwo,twoCountDownLatch);
two.start();
try {
twoCountDownLatch.await();
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
Thread three = new Three(numThree,threeCountDownLatch);
three.start();
try {
threeCountDownLatch.await();
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
logger.info("=====>主线程开始...");
}
}
Object wait()使用
Object 的方法
wait()
:让正在对象上活动的线程进入等待状态,无限期等待,知道被唤醒为止。notify()
:让正在当前对象上等待的线程唤醒。notifyAll()
:唤醒当前对象上处于等待的所有线程。
synchronized()
wait()
和notify()
建立在synchronized
线程同步的基础上。
wait()
:释放当前对象占有的锁。notify
:通知不会释放锁。
wait()
- 锁是锁对象,不是锁住线程。
- Join是Thread对象的,wait是Object对象的,Join的底层实现使wait。
- wait()使用必须在同步范围内不然会报如下的错。
Exception in thread "Thread-3" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at thread.ObjectWaitUse$Three.run(ObjectWaitUse.java:65)
-
wait()作用就是阻塞当前线程等待notify/notifyall()的唤醒,活等待超时后自动唤醒。
-
底层就是ObjectMonitor对象释放了当前对象,丢掉waitSet区域去,然后重新锁住其他的对象。
完整例子,三个线程顺序执行
- demo
public class ObjectWaitUse {
private static final Logger logger = Logger.getLogger(ObjectWaitUse.class);
private static Object objectOne = new Object();
private static Object objectTwo = new Object();
// 子线程是否运行完成的标志
private static boolean oneRun = false;
private static boolean twoRun = false;
class One extends Thread {
@Override
public void run() {
synchronized (objectOne) {
logger.info("====================================》我是One线程");
oneRun = true;
objectOne.notify();
logger.info("=====》One线程执行完成...");
}
}
}
class Two extends Thread {
@Override
public void run() {
synchronized (objectOne) {
try {
if (!oneRun) {
logger.info("=====>线程One没有执行完成,线程二等待中...");
objectOne.wait();
}
synchronized (objectTwo) {
logger.info("====================================》我是Two线程");
objectTwo.notify();
twoRun = true;
logger.info("=====》Two线程执行完成...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Three extends Thread {
@Override
public void run() {
synchronized (objectTwo) {
if (!twoRun) {
try {
logger.info("=====>线程Two没有执行完成,线程三等待中...");
objectTwo.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
logger.info("====================================》我是Three线程");
logger.info("======》Three线程执行完成...");
}
}
}
@Test
public void test1() {
Thread one = new One();
one.start();
Thread two = new Two();
two.start();
Thread three = new Three();
three.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("=====>三个子线程结束...");
}
}
使用ReentrantLock()实现
ReentrantLock()方法介绍
- lock()获得锁资源,如果被其他线程获取,则阻塞等待。
- lockInterruptibly 与lock的不同之处在于它等待锁资源时响应中断,抛出中断状态。
- newCondition 生成一个该锁资源的条件,可以支持完成Object 监控器(wait notify notifyAll)。
newCondition方法介绍
Condition
提供的await()
、signal()
、signalAll()
原理和synchronized
锁对象的wait()
、notify()
、notifyAll()
是一致的,并且其行为也是一样的:
await()
会释放当前锁,进入等待状态;signal()
会唤醒某个等待线程;signalAll()
会唤醒所有等待线程;- 唤醒线程从
await()
返回后需要重新获得锁。
使用例子
- demo
public class ReentrantLockUse {
private static final Logger logger = Logger.getLogger(ObjectWaitUse.class);
/**
* 创建可重入锁
*/
private ReentrantLock reentrantLock = new ReentrantLock();
private Condition oneCondition = reentrantLock.newCondition();
private Condition twoCondition = reentrantLock.newCondition();
private Condition threeCondition = reentrantLock.newCondition();
private boolean oneFlag = false;
private boolean twoFlag = false;
class One extends Thread {
@Override
public void run() {
// 创建锁
reentrantLock.lock();
try {
logger.info("=====》One线程执行完成...");
oneFlag = true;
oneCondition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 释放锁
reentrantLock.unlock();
}
}
}
class Two extends Thread {
@Override
public void run() {
reentrantLock.lock();
try {
while (!oneFlag){
logger.info("----->等待线程one执行完成");
twoCondition.await();
}
twoFlag = true;
logger.info("=====》Two线程执行完成...");
//通知其他线程重新获取锁,该他们执行了
twoCondition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
}
class Three extends Thread {
@Override
public void run() {
reentrantLock.lock();
try {
while (!twoFlag){
logger.info("----->等待线程two执行完成");
twoCondition.await();
}
//通知其他线程重新获取锁,该他们执行了
threeCondition.signalAll();
logger.info("======》Three线程执行完成...");
} catch (Exception e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
}
@Test
public void test1() throws InterruptedException {
Thread one = new One();
one.start();
Thread two = new Two();
two.start();
Thread three = new Three();
three.start();
Thread.sleep(5000);
logger.info("=====>三个子线程结束...");
}
}
CyclicBarrier(回环栅栏)
通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。
private static final Logger logger = Logger.getLogger(CyclicBarrierUse.class);
private CyclicBarrier barrier1 = new CyclicBarrier(2);
private CyclicBarrier barrier2 = new CyclicBarrier(2);
class One extends Thread {
@Override
public void run() {
try {
logger.info("=====》One线程执行完成...");
// 放开栅栏1
barrier1.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Two extends Thread {
@Override
public void run() {
try {
// 放开栅栏1
barrier1.await();
logger.info("=====》Two线程执行完成...");
// 放开栅栏2
barrier2.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Three extends Thread {
@Override
public void run() {
// 放开栅栏2
try {
barrier2.await();
logger.info("======》Three线程执行完成...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}