线程是Java程序中程序执行的基本模型,并且Java语言以及它的API提供了创建和管理线程的一些列丰富的特性
所有的Java程序至少包含一个控制线程,即使是一个只包含一个main()方法的简单的Java程序,特也是在JVM中作为一个线程运行。Java线程可以在任何提供JVM(包括Windows、Linux和Mac OS X)的系统上使用。Java线程API也适用于Android应用程序。
有两种技术可以创建线程:
- Thread,覆写其run()方法
- 实现Runnable。实现run()方法的代码是作为一个单独的线程运行的。
new一个Thread并不会创建一个线程,而是由该对象的start()方法来创建线程的。当调用这个方法时,需要做两件事:
它分配内存并在JVM中初始化一个新线程。
它会调用run()方法,使线程适合在JVM运行。(注意,不要直接调用run方法,而是调用start,让它去调用run)
当该程序运行时,通过JVM创建了两个线程:
- 第一个是父线程,他在main()函数种开始执行。
- 第二个线程在调用Thread对象的start()函数时创建,这个子线程在Summation的run()方法上开始运行 ,在输出累加值后,档次线程从run()方法中退出后,线程终止。
在Windows和Pthreads的线程中共享数据是很简单的,因为共享数据只需要简单的声明为全局的节。
但是,作为一个纯面向对象语言,Java中并没有全局数据的概念。
如果两个或多个线程在Java程序中共享数据,那么实现共享的方式就是将共享对象的引用传递给相应的线程。
在图4.12所示的Java程序中,主线程和求和线程共享Sum类的对象实例。通过适当的getSum()和setSum()方法引用这个共享对象。(您可能想知道为什么我们不使用整数对象,而是设计一个新的sum类。原因是整数类是不可变的——也就是说,一旦它的值被设置,它就不能改变。)
图4-12
import java.util.stream.IntStream;
public class Driver {
public static void main(String[] args) {
if (args.length > 0) {
if (Integer.parseInt(args[0]) < 0)
System.err.println(args[0] + " must be >= 0.");
else {
Sum sumObject = new Sum();
int upper = Integer.parseInt(args[0]);
Thread thrd = new Thread(new Summation(upper, sumObject));
thrd.start();
try {
thrd.join();
System.out.println
("The sum of "+upper+" is "+sumObject.getSum());
} catch (InterruptedException ie) { }
}
}
else
System.err.println("Usage: Summation <integer value>");
}
}
class Sum{
private int sum;
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
}
class Summation implements Runnable{
private int upper;
private Sum sumValue;
public Summation(int upper, Sum sumValue) {
this.upper = upper;
this.sumValue = sumValue;
}
@Override
public void run() {
int reduce = IntStream.range(0, upper).reduce(0, (count, current) -> count += current);
sumValue.setSum(reduce);
}
在Pthreads和Windows中,分别使用pthread_join()以及WaitForSingleObject()来执行对子线程的等待。在Java中可以使用join()方法来实现相同的功能(注意,join方法会抛出InterruptedException异常,我们可以忽略)。
如果需要等待多个子线程,那么可以使用for循环,来实现这样的功能,当然Java7提供了类似于CountDownLatch等多线程模型