线程的概念及创建任务与线程
引言
多线程使得程序中的多个任务可以同时执行。
java的重要功能之一就是内部支持多线程————在一个程序中运行同时运行多个任务。在许多程序设计语言中,多线程都是通过调用依赖于系统的过程或函数来实现的。在本文中,将介绍线程的该奶奶及如何在Java中运行一个多线程的例子。
一、线程的概念
概念
首先,何谓线程? 一个程序可能包含多个可以同时运行的任务,线程是指一个任务从头至尾的执行流程。
线程提供了运行一个任务的机制,对于Java而言,可以在一个程序中并发地启动多个线程,这些线程可以在多处理器系统上同时运行。若只有一个处理器,则多个线程共享单个CPU。
在单处理器系统中,多个线程共享CPU时间成为时间分享,而操作系统负责调度及分配资源给它们。这种安排之所以是可行的,是因为CPU的大部分时间都是空闲的。例如,在等待用户输入数据时,CPU什么都不做。
多线程可以使程序反应更快、交互性更强、执行效率更高,例如,一个好的文字处理程序允许在输入文字的同时打印或者保存文件。在一些情况下,即使是在单处理器系统上,多线程程序的运行速度也比单线程程序更快。Java对多线程程序的创建和运行,以及锁定资源以避免冲突提供了非常好的支持。
Java中的线程
可以在程序中创建附加的线程以执行并发任务在Java中,每个任务都是Runnable
接口的一个实例,也称为可运行对象(runnable object)。
Java中,从本质上来讲,线程就是一个便于任务执行的对象。
二、如何创建任务与线程
如上一小节中所讲,任务就是对象。为了创建任务,必须首先为这个任务定义一个实现Runnable
接口的类(否则如何创建这个实例呢?)。Runnable
接口非常简单,它只包含一个run
方法,因此只要我们创建的类中也包含这个方法即可。而这个方法的作用就是告诉系统线程将如何运行的。如我们可以如以下的形式定义一个实现某任务的类:
public class TaskClass implements runnable {
public TaskClass(...) {}
@Override
public void run()
}
人任务必须在线程中执行,Thread
类包括创建线程的构造方法以及控制线程的很多有用的方法,如对于上面的TaskClass类,可以使用如下的语句为其创建任务的线程:
TaskClass task = new TaskClass(...); // 先创建一个任务的实例
Thread thread = new Thread(task); // 将可运行对象传入
然后调用start()
方法告诉Java虚拟机该线程准备运行:
thread.start()
之后,Java虚拟机通过调用任务的run()
方法执行任务。
在下面的例子中,会创建3个任务以及3个运行这些任务的线程,其中:
- 任务1 打印字母 ‘a’ 100次
- 任务2 打印从1到100的整数
首先,是创建两个分别实现这两个任务的类:
// PrintChar.java
package learning_java.book.concurrency;
public class PrintChar implements Runnable {
private char charToPrint;
private int times;
public PrintChar(char c, int t) {
charToPrint = c;
times = t;
}
@Override
public void run() {
for (int i = 0; i < times; i ++) {
System.out.print(charToPrint);
}
}
}
// PrintNum.java
package learning_java.book.concurrency;
public class PrintNum implements Runnable{
private int lastNum;
public PrintNum(int n) {
lastNum = n;
}
public void run() {
for (int i = 1; i <= lastNum; i ++) {
System.out.print(" " + i);
}
}
public static void main(String[] args) {
new PrintNum(10).run();
}
}
之后,再创建一个主方法的类,创建这两个任务的实例,并为其创建线程并运行。
//TaskThreadDemo.java
package learning_java.book.concurrency;
public class TaskThreadDemo {
public static void main(String[] args) {
Runnable printA = new PrintChar('a', 100);
Runnable print100 = new PrintNum(100);
Thread thread1 = new Thread(printA);
Thread thread2 = new Thread(print100);
thread1.start();
thread2.start();
}
}
输出:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1aaaaaaaaaaa 2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 3a 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
在这短程序中,若从结果看不到并发运行三个线程的效果,那么就要增加打印字符与数字的个数,如更改为打印1000次。
最后,还有一点需要注意的是,在任务类中的run()
方法知名如何完成这个任务,如果使用Thread类的方法为其构建线程并运行的话,Java虚拟机会自动调用该方法,而无需特意调用它。如果手动在代码中调用一个实例的run()
方法,则效果只是在同一个线程中执行该方法,而不是有新线程被启动。