Java并发2——Thread对象

Java线程由Thread类表示。下面开始讨论Thread类!


定义和启动线程

实例化一个Thread对象,有两种实现方法:

  • 实现Runnable接口Runnable接口仅定义了方法run,用于包含在单独线程中运行的代码。将Runnable对象传递给Thread构造函数,如下所示:
    public class HelloRunnable implements Runnable {
    
        public void run() {
            System.out.println("Hello from a thread!");
        }
    
        public static void main(String args[]) {
            (new Thread(new HelloRunnable())).start();
        }
    
    }
  • 继承Thread类。Thread类实现了Runnable接口,不过其run方法为空。所以可以继承Thread类,然后覆盖run方法,如下所示:
    public class HelloThread extends Thread {
    
        public void run() {
            System.out.println("Hello from a thread!");
        }
    
        public static void main(String args[]) {
            (new HelloThread()).start();
        }
    
    }

这两种方法,应该选择哪一种呢?其中,实现Runnable接口更为通用,因为Java不允许多重继承,如果继承了Thread类,就不能继承其他类,但是实现接口没关系。继承Thread类则更为简单,使用Thread包含一些方法很方便,在一些简单的应用中很好用。

两种方法都通过Thread.start启动线程。Thread类还包含许多用于线程管理的有用犯非法,包括一些用于改变及获得线程状态的静态方法。

暂停线程

Thread.sleep暂停当前线程。主要作用是让出处理器时间给其他线程或应用。

有两个重载的sleep方法:一个指定微秒的睡眠时间,一个指定纳秒的睡眠时间。需要注意的是,指定的睡眠时间不能保证完全准确,睡眠多长时间和底层OS相关。另外,睡眠过程可被打断。在任何情况下,都不要用sleep的确切时间进行程序设计。

如SleepMessages所示,它会每4秒打印一条信息:

public class SleepMessages {
    public static void main(String args[]) throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };

        for (int i = 0;
             i < importantInfo.length;
             i++) {
            //Pause for 4 seconds
            Thread.sleep(4000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}
从main抛出的异常可以看出,当sleep被其他线程打断时,会抛出InterruptedException异常。

线程中断

中断,即让线程停止运行。线程究竟如何中断由自己实现,一般直接结束线程。

Thread通过调用interrupt中断线程。那么一个线程如何中断?

中断支持

一个线程如何中断,取决于线程正在干什么。如果一个线程经常调用会抛出InterruptedExceptiond的方法,则在抛出异常后,会直接从run方法返回,从而中断。我们对上面的SleepMessages稍微修改一下以支持中断:

for (int i = 0; i < importantInfo.length; i++) {
    // Pause for 4 seconds
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // We've been interrupted: no more messages.
        return;
    }
    // Print a message
    System.out.println(importantInfo[i]);
}
许多会抛出InterruptedException的方法( 如sleep),目的是在被中断后取消当前操作,并立即返回。

那么,如果一个线程运行很长时间,但是就没有调用抛出InterruptedException的方法咋办?这时可以定期调用Thread.interrupted方法,该方法在接收到中断操作时返回true。例如:

for (int i = 0; i < inputs.length; i++) {
    heavyCrunch(inputs[i]);
    if (Thread.interrupted()) {
        // We've been interrupted: no more crunching.
        return;
    }
}
在上例中,通过判断线程是否被中断,来觉得是否应该返回。对于比较复杂的程序,直接抛出异常比较好:

if (Thread.interrupted()) {
    throw new InterruptedException();
}
从而能把精力集中在catch子句的编写。

中断状态flag

中断机制是通过内部的一个中断状态标签来实现的。调用Thread.interrupt时会设置该flag。当通过Thread.interrupted检测中断状态时,该flag被清除。而通过非静态方法isInterrupted检查,则不会清除该flag。

Joins

join方法使一个线程在另外一个线程结束之后再执行。假如t是当前要运行的Thread

t.join();
调用join之后,当前线程暂停运行直到线程t结束。join有个重载方法,可以定义等待的时间,不过和sleep方法一样,这个时间也不是完全准确的,在被打断时也抛出InterruptedException。


实例:

SimpleThreads包含两个线程,首先是main线程,然后在main里新建了一个MessageLoop线程,并且等待该线程运行完成,如果MessageLoop运行线程过长,main就打断它。

public class SimpleThreads {

    // Display a message, preceded by
    // the name of the current thread
    static void threadMessage(String message) {
        String threadName =
            Thread.currentThread().getName();
        System.out.format("%s: %s%n",
                          threadName,
                          message);
    }

    private static class MessageLoop 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++) {
                    // Pause for 4 seconds
                    Thread.sleep(4000);
                    // Print a message
                    threadMessage(importantInfo[i]);
                }
            } catch (InterruptedException e) {
                threadMessage("I wasn't done!");
            }
        }
    }

    public static void main(String args[])
        throws InterruptedException {

        // Delay, in milliseconds before
        // we interrupt MessageLoop
        // thread (default one hour).
        long patience = 1000 * 60 * 60;

        // If command line argument
        // present, gives patience
        // in seconds.
        if (args.length > 0) {
            try {
                patience = Long.parseLong(args[0]) * 1000;
            } catch (NumberFormatException e) {
                System.err.println("Argument must be an integer.");
                System.exit(1);
            }
        }

        threadMessage("Starting MessageLoop thread");
        long startTime = System.currentTimeMillis();
        Thread t = new Thread(new MessageLoop());
        t.start();

        threadMessage("Waiting for MessageLoop thread to finish");
        // loop until MessageLoop
        // thread exits
        while (t.isAlive()) {
            threadMessage("Still waiting...");
            // Wait maximum of 1 second
            // for MessageLoop thread
            // to finish.
            t.join(1000);
            if (((System.currentTimeMillis() - startTime) > patience)
                  && t.isAlive()) {
                threadMessage("Tired of waiting!");
                t.interrupt();
                // Shouldn't be long now
                // -- wait indefinitely
                t.join();
            }
        }
        threadMessage("Finally!");
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值