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线程一直等待的情况


无知
0 声望1 粉丝

思考中