Java学习之进程和线程 – skyWalker

在并发程序中,存在两个基本的概念:进程和线程。相对于进程,线程需要更少的资源(线程也被称为轻量级进程),并且存在于进程中,反过来进程中至少存在一个线程(主线程)。一个进程拥有独立的执行环境,通常拥有完整的,私有的基本运行时资源,每个进程都有自己的内存空间。一般情况下,进程通常做为应用程序的同义词,也就是往往将某个应用程序看做进程,而实际上一个运行的应用程序可能有多个互相协作的进程组成。大多数操作系统支持进程间通信(Inter Process Communication,IPC),比如管道、套接字和内存共享等,IPC不仅支持系统中的进程通信也支持不同系统中的进程通信。

线程同样需要执行环境,不同于进程有独立的执行环境的是,线程共享所属进程的资源,包括内存和打开的文件,这能够使通信更加高效,但也存在潜在的问题。多线程是Java平台的基本特性,在Java中每个应用程序至少包含一个线程,从程序员的角度出发,程序从一个线程启动,该线程称为主线程,主线程负责创建其它线程。

Java中每个线程对应一个Thread对象,每个线程都拥有标识自己的名字,可以在创建Thread对象时指定名字,若没指定将会自动生成形如Thread-n的名字,n为整数。在Java中有两种方法创建线程,第一种方法是实现Runnable接口,该接口定义了唯一的方法run,在该方法中可以编写线程要执行的工作,当线程启动时将调用run方法。第二种方法是继承Thread类,Thread实现了Runnable接口,但run方法不做任何事情,所以子类需要提供自己的run方法实现以覆盖父类的方法。无论使用上述方法中的哪种创建线程,都需要调用Thread对象的start方法启动线程。这两种方法推荐使用第一种创建线程,因为第二种方法要求线程必须是Thread类的子类,而第一种方法则更为灵活。

Thread类提供了一些静态方法和非静态方法用于对线程操作和管理。其中静态方法作用于当前线程,非静态方法作用于调用该方法的线程对象上。下面介绍几个经常使用的方法,包括sleep、interrupted、jion,最后给出演示这些方法如何使用及实际执行情况的代码。

sleep()为静态方法,当执行Thread.sleep()时会是当前线程暂停指定的时间,这样其它线程或者进程可以获取处理器的时间。存在两个重载的sleep方法,一个方法的参数为毫秒,另一个方法的参数为毫秒和纳秒。但休眠的时间不能确保就为方法指定的时间,因为休眠时间受限于操作系统,另外休眠也可以被中断,因此不能认为调用了sleep方法,线程肯定会暂停指定的时间。当其它线程中断当前线程正在进行的sleep方法时,该方法抛出InterruptedException。

中断指示线程应该停止正在做的工作,然后由程序员决定如何响应中断,但是通常是结束线程。一个线程通过在要被中断的线程对象上调用interrupt()方法来中断线程,这就要求被中断的线程支持它自己的中断。如果被中断线程调用了抛出InterruptedException的方法,那么当线程捕获到该异常时就可以在run方法中退出,如果被中断线程没有调用抛出InterruptedException的方法,则需要执行Thread.interrupted()以判断当前线程是否接收到了中断,若接收到中断该方法返回true。

Join方法可以使一个线程等待另一个线程执行完毕后再执行。比如t表示将要执行的线程,t.join()导致当前线程暂停执行直到t执行完毕。重载的join方法允许程序员指定等待的时间,但同sleep方法一样,等待的时间依赖于操作系统,所以也不能认为join方法会等待指定的时间。在收到中断时,join也会抛出InterruptedException。

在介绍了很多概念性的知识后,现在看看如何编写线程代码,以及这些代码的运行情况。

package learning;public class ThreadLearning {static void showThreadMessage(String message) {        String threadName = Thread.currentThread().getName();        System.out.format("%1$tF %1$tH:%1$tM:%1$tS:%1$tL %2$s: %3$s%n", System.currentTimeMillis(),threadName, message);       }private static class MessageThread implements Runnable {        public void run() {            String importantInfo[] = {                "Mares eat oats",                "Does eat oats",                "Little lambs eat ivy",                "A kid will eat ivy too"            };            try {                for (int i = 0; i < importantInfo.length; i++) {                showThreadMessage(importantInfo[i]);                    Thread.sleep(4000);                    }            } catch (InterruptedException e) {            showThreadMessage("I was iterrupted and wasn't done!");            }        }    }public static void main(String[] args) throws InterruptedException {        long patience = 1000 * 60;        showThreadMessage("Starting MessageThread thread");        long startTime = System.currentTimeMillis();        Thread t = new Thread(new MessageThread());        t.start();        showThreadMessage("Waiting for MessageThread thread to finish");        while (t.isAlive()) {        showThreadMessage("Still waiting...");            t.join(1000);            if (((System.currentTimeMillis() - startTime) > patience) &&t.isAlive()) {            showThreadMessage("Tired of waiting!");                t.interrupt();                t.join();            }        }        showThreadMessage("Finally!");}}

执行上述代码的输出为:

2014-08-27 14:51:46:656 main: Starting MessageThread thread2014-08-27 14:51:46:738 main: Waiting for MessageThread thread to finish2014-08-27 14:51:46:740 main: Still waiting...2014-08-27 14:51:46:739 Thread-0: Mares eat oats2014-08-27 14:51:47:761 main: Still waiting...2014-08-27 14:51:48:762 main: Still waiting...2014-08-27 14:51:49:763 main: Still waiting...2014-08-27 14:51:50:744 Thread-0: Does eat oats2014-08-27 14:51:50:764 main: Still waiting...2014-08-27 14:51:51:765 main: Still waiting...2014-08-27 14:51:52:766 main: Still waiting...2014-08-27 14:51:53:767 main: Still waiting...2014-08-27 14:51:54:746 Thread-0: Little lambs eat ivy2014-08-27 14:51:54:768 main: Still waiting...2014-08-27 14:51:55:769 main: Still waiting...2014-08-27 14:51:56:770 main: Still waiting...2014-08-27 14:51:57:771 main: Still waiting...2014-08-27 14:51:58:749 Thread-0: A kid will eat ivy too2014-08-27 14:51:58:772 main: Still waiting...2014-08-27 14:51:59:773 main: Still waiting...2014-08-27 14:52:00:775 main: Still waiting...2014-08-27 14:52:01:776 main: Still waiting...2014-08-27 14:52:02:750 main: Finally!

通过输出可以发现线程休眠的时间并非精确的4秒,如果将上面的long patience = 1000 * 60改为long patience = 1000 * 6,执行结果如下:

2014-08-27 14:58:04:555 main: Starting MessageThread thread2014-08-27 14:58:04:622 main: Waiting for MessageThread thread to finish2014-08-27 14:58:04:622 Thread-0: Mares eat oats2014-08-27 14:58:04:623 main: Still waiting...2014-08-27 14:58:05:626 main: Still waiting...2014-08-27 14:58:06:627 main: Still waiting...2014-08-27 14:58:07:630 main: Still waiting...2014-08-27 14:58:08:626 Thread-0: Does eat oats2014-08-27 14:58:08:631 main: Still waiting...2014-08-27 14:58:09:632 main: Still waiting...2014-08-27 14:58:10:633 main: Tired of waiting!2014-08-27 14:58:10:634 Thread-0: I was iterrupted and wasn't done!2014-08-27 14:58:10:636 main: Finally!

由于主线程在等待MessageThread执行6秒后就会调用MessageThread的interrupt()方法,MessageThread被中断。t.join(1000)决定了当前线程等待t线程的时间,也可以从上面的输出中验证,main线程打印Still waiting…的时间间隔大概为1秒,并不精确。如果将join中的毫秒数调整到20000,那么当前主线程将不会继续执行,直到20秒时间到期或者t执行完毕。这说明当t在join中的指定参数时间内不能执行完毕的话,调用t.join(1000)的线程将会继续执行。

就微笑着同清风合力染绿大地,这样才算善待生命,不负年华。

Java学习之进程和线程 – skyWalker

相关文章:

你感兴趣的文章:

标签云: