1、使用Thread.join()方法
可以在一个线程中调用另一个线程的join()方法,使得该线程等待另一个线程执行完成后再继续执行。可以通过在需要等待的线程后面调用join()方法的方式来控制线程的执行顺序。
Thread t1 = new Thread(new Runnable() {
public void run() {
// 执行一些任务
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
// 等待t1线程执行完成
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 继续执行一些任务
}
});
t1.start();
t2.start();
在这个例子中,t2线程在执行之前会等待t1线程执行完成,这样就可以保证t1先执行。
2、使用Lock和Condition
可以使用Lock和Condition来控制线程的执行顺序。Lock可以创建多个Condition对象,每个Condition对象可以控制一个线程的执行顺序。使用Condition的await()方法可以使线程等待,使用signal()方法可以唤醒等待的线程。
class ShareResourceLock{
// 线程执行的条件 1:线程1执行 2:线程2执行 3:线程3执行
int number =1;
// 锁
Lock lock = new ReentrantLock();
// 从锁中获得3个条件变量
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
// 第一个线程run之后执行的方法
public void f1(){
lock.lock();
try {
// 如果条件值不为1 就挂起等待
while(number!=1){
System.out.println(Thread.currentThread().getName() + " await...");
condition1.await();
}
// 故意阻塞100毫秒,看看其他的线程会不会不再排队
int i= new Random().nextInt(2000);
Integer sleepTime = 1000 + i;
Thread.sleep(sleepTime);
System.out.println(Thread.currentThread().getName() + " execute " + sleepTime);
System.out.println("------1--------");
// 线程1 执行完毕 把变量设置为2
number = 2;
// 唤醒第2个条件变量
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 不管抛没抛出异常都要解锁,防止线程死锁
lock.unlock();
}
}
public void f2(){
lock.lock();
try {
while(number!=2){
System.out.println(Thread.currentThread().getName() + " await...");
condition2.await();
}
int i= new Random().nextInt(2000);
Integer sleepTime = 1000 + i;
Thread.sleep(sleepTime);
System.out.println(Thread.currentThread().getName() + " execute " + sleepTime);
System.out.println("------2--------");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void f3(){
lock.lock();
try {
while(number!=3){
System.out.println(Thread.currentThread().getName() + " await...");
condition3.await();
}
int i= new Random().nextInt(2000);
Integer sleepTime = 1000 + i;
Thread.sleep(sleepTime);
System.out.println(Thread.currentThread().getName() + " execute " + sleepTime);
System.out.println("------3--------");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class ThreadOrderExecute {
public static void main(String[] args) throws InterruptedException {
ShareResourceLock shareDataLock = new ShareResourceLock();
Thread t1 = new Thread(()->shareDataLock.f1(),"aa");
Thread t2 = new Thread(()->shareDataLock.f2(),"bb");
Thread t3 = new Thread(()->shareDataLock.f3(),"cc");
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
}
}
在这个例子中,t1线程执行完成后会唤醒t2线程,t2线程执行完成后会唤醒t3线程,这样就可以保证线程的执行顺序。注意,await()和signal()方法必须在lock.lock()和lock.unlock()之间调用,否则会抛出IllegalMonitorStateException异常。
这些方法都可以实现线程按照特定顺序执行的效果,具体选择哪种方法取决于具体的情况和需求。
3、举一个反面的例子,注意执行顺序
public class ThreadOrderExecute2 {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
// 从锁中获得3个条件变量
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
lock.lock();
try {
// 如果条件值不为1 就挂起等待
System.out.println("------1--------");
// 唤醒第2个条件变量
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 不管抛没抛出异常都要解锁,防止线程死锁
lock.unlock();
}
}
},"aa");
Thread t2 = new Thread(new Runnable(){
@Override
public void run() {
lock.lock();
try {
System.out.println("------t2 await--------");
condition2.await();
// 如果条件值不为1 就挂起等待
System.out.println("------2--------");
// 唤醒第2个条件变量
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
},"bb");
Thread t3 = new Thread(new Runnable(){
@Override
public void run() {
lock.lock();
try {
System.out.println("------t3 await--------");
condition3.await();
// 如果条件值不为1 就挂起等待
System.out.println("------3--------");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 不管抛没抛出异常都要解锁,防止线程死锁
lock.unlock();
}
}
},"cc");
// 正确的打开方式
// t3.start();
// Thread.sleep(1000);
// t2.start();
// Thread.sleep(1000);
// t1.start();
// 存在问题的打卡方式,可能会出现t1线程执行了condition2.signal();
// 但是t2线程还没执行condition2.await();所以会出现t2线程一直等待的情况
t1.join();
t2.join();
t3.join();
}
}
在上面这个例子中,线程t1,t2,t3的执行顺序影响比较大,如果按照t1,t2,t3的顺序执行,可能会出现t1线程执行了condition2.signal(); 但是t2线程还没执行condition2.await();最终产生的结果就是t1执行了condition2.signal(),但是t2线程并没有接受到,造成t2线程一直等待的情况
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。