java实现多线程的方式,一种是直接继承Thread,由于java是单继承的,所以这种方式会限制我们以后需要继承自己的类,另外一种是实现Runnable接口,也是推荐使用的,因为接口可以实现多个。如下代码:
public class ThreadTest implements Runnable{
public static void main(String[] args) throws InterruptedException {
ThreadTest r = new ThreadTest();
Thread t = new Thread(r);
t.start();
System.out.print("world ");
}
@Override
public void run() {
System.out.print("hello ");
}
}
一般情况下,如果程序按照顺序执行,我们可能会认为输出 hello world,因为start()方法是用来启动线程。所以我们一般都会认为调用start的时候就会执行这个线程的run方法,但是实际上start方法只是改变线程的状态而已,一个线程需要获得资源才能够执行,比如内存,CPU。而上面的代码输出的是world hello,所以我的理解是start方法只是将线程的状态告诉操作系统这个线程当前处于可执行状态,系统会在合适的时候分配资源给这个线程去完成任务。
那么如果我希望上面的程序输出hello world怎么办?这时候就需要调用join方法了。
The join
method allows one thread to wait for the completion of another. If t
is a Thread
t.join();
causes the current thread to pause execution until t
's thread terminates.
join方法允许让一个线程等待另一个线程完成执行。如果t是一个正在执行的线程对象,调用t.join()会导致当前线程暂停执行,一直到 t 这个线程执行完成。将代码修改:
ThreadTest r = new ThreadTest();
Thread t = new Thread(r);
t.start();
t.join();//这里加入到当前线程
System.out.print("world ");
那么结果就是 hello world。由于join方法会阻塞当前线程的执行,所以这个方法也像sleep方法一样会抛出InterruptedException异常,当然你也可以加入一个等待时间,如果过了这个指定的时间这个线程还是没有执行完的话那就回到当前线程,例如我们把代码修改成如下的样子,那么结果还是world hello
public class ThreadTest implements Runnable{
public static void main(String[] args) throws InterruptedException {
ThreadTest r = new ThreadTest();
Thread t = new Thread(r);
t.start();
t.join(1000);
System.out.print("world ");
}
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print("hello ");
}
}
这里join方法等了1秒钟,但是这个线程的执行需要两秒钟,所以这个线程还没来得及输出hello的时候当前线程就继续执行了。就像你去打的,突然忘了拿东西,然后叫司机等你十分钟,但是时间到了你还没来,司机已经走了。还有就是这个join方法的这个等待时间是依赖于系统的,所以不一定真的会等那么久,比如你的时钟和司机的时钟可能不一样,司机的时钟比较快,你的才过去8分钟,但是司机的已经是10分钟了。这里说的快应该说的是计数的速度,而不是我们平时说的快,我们平时说的快慢是指我们的时间与标准的时间不一样。