线程与进程的关系与特点:
a.进程
1.运行性 程序运行时才会产生
2.独立性 进程与进程之间互不干扰
3.并发性 多个进程在同一处理器上运行,它们是交替执行
并行 同一时刻不同进程在不同处理器上同时执行
b.线程
进程的一个子单元
1.并发性
2.独立性
3.数据共享
主线程:最后一个关闭
线程的实现方法:
1.Thread类
2.Runnable接口
3.Callable 和 Future
使用Thread类实现:
创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
案例:
class BoilThread extends Thread { //烧开水的线程
public voidrun() {
try {
System.out.println("开始烧水...");
Thread.sleep(10000); //假设烧水需要10秒
System.out.println("水烧开了。");
} catch (InterruptedException ie) { ie.printStackTrace(); }
}
}
class WashThread extends Thread { //洗茶杯的线程
public void run() {
try {
for (int i =1; i <= 5; i++){ //洗5个茶杯
System.out.print("开始洗第" + i +"个茶杯...");
Thread.sleep(1500); //假设每洗一个茶杯需要1.5秒
System.out.println("第" + i +"个茶杯洗干净。");
}
} catch (InterruptedException ie) { ie.printStackTrace(); }
}
}
public class MakeTea {
public staticvoid main(String[] args){
new BoilThread().start(); //启动烧水线程
new WashThread().start(); //启动洗茶杯线程
}
}
使用Runnable接口实现:
该方法主要是重写run()方法,run() 可以调用其他方法,使用其他类,并声明变量,就像主线程一样。当调用线程的start()方法时,会执行run()方法里面的代码;
案例:
class ShowDateLabelextends JLabelimplements Runnable { //实现Runnable接口
private int sleepTime; //休眠时间
public ShowDateLabel(int sleepTime) {
this.sleepTime = sleepTime;
new Thread(this).start(); //启动线程
}
public void run() { //实现Runnable接口中的run方法
try {
while (true) {
this.setText(new Date().toString()); //显示当前时间
Thread.sleep(sleepTime);
}
} catch (InterruptedException ie) { ie.printStackTrace(); }
}
}
public class ClockFrame extends JFrame {
public ClockFrame() {
Containercp = this.getContentPane();
cp.setLayout(new GridLayout(3, 1));
cp.add(new ShowDateLabel(1000));
cp.add(new ShowDateLabel(3000));
cp.add(new ShowDateLabel(5000));
……
}
}
使用Callable 和 Future实现:
- 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
- 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
- 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
案例:
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
创建线程的三种方式的对比
1. 采用实现 Runnable、Callable 接口的方式创见多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。