java线程的顺序执行顺序控制

今天看到一个关于如何让线程顺序执行的博文,感觉很有意思。

当然,例子是人家的

public class JoinTest2 {

    public static void main(String[] args) {
         final Thread t1 = new Thread(new Runnable() {
             @Override
            public void run() {
                System.out.println("t1");
            }
        });

        final Thread t2 = new Thread(new Runnable() {
             @Override
            public void run() {
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2");
            }
        });

        Thread t3 = new Thread(new Runnable() {
             @Override
            public void run() {
                try {
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t3");
            }
        });

        t3.start();
        t2.start();
        t1.start();
    }
}

从上面的代码中可以看出,创建了三个线程t1,t2,t3,这组带码的意思是三个线程顺序执行,即t1->t2->t3。而完成整个顺序过程知识简单的使用了一个Tread类(java.lang.Thread)的join方法。在java(J2SE8)的官方的api文档中可以看到

java线程的顺序执行顺序控制

join()方法是等待当前线程执行结束。

在这里我想到了Object类(java.lang.Object)中的wait方法,这就是为什么我要写篇文章:做一个对比。

在api文档中是这样描述的

java线程的顺序执行顺序控制

第一个wait()方法描述的意思是,导致当前的线程处于等待状态,直至别的线程使用notify()或者notifyAll()方法唤醒它。

使用wait和notify时有一个比较坑爹的地方是必须要在同步锁内使用,看notify的api描述

/**
     * Wakes up a single thread that is waiting on this object's
     * monitor. If any threads are waiting on this object, one of them
     * is chosen to be awakened. The choice is arbitrary and occurs at
     * the discretion of the implementation. A thread waits on an object's
     * monitor by calling one of the {@code wait} methods.
     * <p>
     * The awakened thread will not be able to proceed until the current
     * thread relinquishes the lock on this object. The awakened thread will
     * compete in the usual manner with any other threads that might be
     * actively competing to synchronize on this object; for example, the
     * awakened thread enjoys no reliable privilege or disadvantage in being
     * the next thread to lock this object.
     * <p>
     * This method should only be called by a thread that is the owner
     * of this object's monitor. A thread becomes the owner of the
     * object's monitor in one of three ways:
     * <ul>
     * <li>By executing a synchronized instance method of that object.
     * <li>By executing the body of a {@code synchronized} statement
     *     that synchronizes on the object.
     * <li>For objects of type {@code Class,} by executing a
     *     synchronized static method of that class.
     * </ul>
     * <p>
     * Only one thread at a time can own an object's monitor.
     *
     * @throws  IllegalMonitorStateException  if the current thread is not
     *               the owner of this object's monitor.
     * @see        java.lang.Object#notifyAll()
     * @see        java.lang.Object#wait()
     */

所以我写了如下的代码,看看notify和wait时如何工作

public class threadT implements Runnable
{

	public String name = null;
	
	public threadT(String name)
	{
		this.name = name;
	}
	
	@Override
	public void run() 
	{
		synchronized (this) {
			System.out.println(name);
			notify();
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
        
    	Thread thread = new Thread(new threadT("run"));
    	synchronized (thread) {
			System.out.println("step1");
			thread.start();
			System.out.println("step2");
			thread.wait();
			System.out.println("step3");
		}

    }
}

其执行结果如下

step1
step2
run
step3

为什么线程的业务功能看似在调用wait()的时候执行,而不是在调用start()的时候?

其原因在start方法的调用机制,当调用start的时候,虚拟机会开两个线程:一个线程调用start方法,另一个线程执行run函数。如果让线程在调用start之后休息10ns(thread.sleep(10)),那么执行就正常了。

step1
run
step2
step3

java线程的顺序执行顺序控制