Thread 方法
下表列出了Thread类的一些重要方法:
序号 | 方法描述 |
1 | public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 |
2 | public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。 |
3 | public final void setName(String name) 改变线程名称,使之与参数 name 相同。 |
4 | public final void setPriority(int priority) 更改线程的优先级。 |
5 | public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。 |
6 | public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。 |
7 | public void interrupt() 中断线程。 |
8 | public final boolean isAlive() 测试线程是否处于活动状态。 |
测试线程是否处于活动状态。 上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。
序号 | 方法描述 |
1 | public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
2 | public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 |
3 | public static boolean holdsLock(Object x) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。 |
4 | public static Thread currentThread() 返回对当前正在执行的线程对象的引用。 |
5 | public static void dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。 |
实例
如下的ThreadClassDemo 程序演示了Thread类的一些方法:
DisplayMessage.java 文件代码:
// 文件名 : DisplayMessage.java// 通过实现 Runnable 接口创建线程publicclassDisplayMessageimplementsRunnable { privateStringmessage; publicDisplayMessage(Stringmessage) { this.message=message; } publicvoidrun() { while(true) { System.out.println(message); } } }
GuessANumber.java 文件代码:
// 文件名 : GuessANumber.java// 通过继承 Thread 类创建线程publicclassGuessANumberextendsThread { privateintnumber; publicGuessANumber(intnumber) { this.number=number; } publicvoidrun() { intcounter=0; intguess=0; do { guess= (int) (Math.random() *100+1); System.out.println(this.getName() +" guesses "+guess); counter++; } while(guess!=number); System.out.println("** Correct!"+this.getName() +"in"+counter+"guesses.**"); } }
ThreadClassDemo.java 文件代码:
// 文件名 : ThreadClassDemo.javapublicclassThreadClassDemo { publicstaticvoidmain(String [] args) { Runnablehello=newDisplayMessage("Hello"); Threadthread1=newThread(hello); thread1.setDaemon(true); thread1.setName("hello"); System.out.println("Starting hello thread..."); thread1.start(); Runnablebye=newDisplayMessage("Goodbye"); Threadthread2=newThread(bye); thread2.setPriority(Thread.MIN_PRIORITY); thread2.setDaemon(true); System.out.println("Starting goodbye thread..."); thread2.start(); System.out.println("Starting thread3..."); Threadthread3=newGuessANumber(27); thread3.start(); try { thread3.join(); }catch(InterruptedExceptione) { System.out.println("Thread interrupted."); } System.out.println("Starting thread4..."); Threadthread4=newGuessANumber(75); thread4.start(); System.out.println("main() is ending..."); } }
运行结果如下,每一次运行的结果都不一样。
Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......
通过 Callable 和 Future 创建线程
- 1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
- 2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
- 3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
- 4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
publicclassCallableThreadTestimplementsCallable<Integer> { publicstaticvoidmain(String[] args) { CallableThreadTestctt=newCallableThreadTest(); FutureTask<Integer>ft=newFutureTask<>(ctt); for(inti=0;i<100;i++) { System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i); if(i==20) { newThread(ft,"有返回值的线程").start(); } } try { System.out.println("子线程的返回值:"+ft.get()); } catch (InterruptedExceptione) { e.printStackTrace(); } catch (ExecutionExceptione) { e.printStackTrace(); } } @OverridepublicIntegercall() throwsException { inti=0; for(;i<100;i++) { System.out.println(Thread.currentThread().getName()+" "+i); } returni; } }
创建线程的三种方式的对比
- 1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
- 2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
线程的几个主要概念
在多线程编程时,你需要了解以下几个概念:
- 线程同步
- 线程间通信
- 线程死锁
- 线程控制:挂起、停止和恢复
多线程的使用
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。
通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。
请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间!