线程和进程
线程和进程是两个非常容易混淆的概念。进程是资源分配的基本单位,又是调度运行的基本单位。进程则是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。
举个栗子来讲:打开QQ就是启动了一个进程,打开迅雷也是启动了一个线程;而迅雷创建一个下载任务就是创建一个线程,QQ打开消息对话框也是一个线程。
进程和线程就是父与子的关系,一个进程可以有多个线程,但是一个线程只能存在于一个进程当中。
创建一个线程
继承Thread创建
创建线程类
public class MyThread1 extends Thread { private static int num = 0; public MyThread1(){ num++; } @Override public void run(){ System.out.println("线程"+num); }}
创建线程对象并启动线程
public class MyThreadTest1 { public static void main(String[] args) throws Exception { MyThread1 thread1 = new MyThread1(); thread1.start(); }}
启动线程要用start()方法,如果是用run()启动的话,实际上就是在当前进程中执行了方法,并不会创建线程,如下代码:
public class MyThread1 extends Thread { private String name; public MyThread1(String name){ this.name = name; } @Override public void run() { System.out.println("name:"+name+" 子线程ID:"+Thread.currentThread().getId()); }}
public class MyThreadTest1 { public static void main(String[] args) { System.out.println("当前线程ID是 "+Thread.currentThread().getId()); MyThread1 myThread1 = new MyThread1("thread1"); myThread1.run(); MyThread1 myThread2 = new MyThread1("thread2"); myThread2.start(); }}
运行结果
当前线程ID是 1name:thread1 子线程ID:1name:thread2 子线程ID:13
实现Runnable创建
创建对象实现Runnable
public class Runnable1 implements Runnable { @Override public void run() { System.out.println("子线程ID: " + Thread.currentThread().getId()); }}
创建并启动线程
public class RunnableTest1 { public static void main(String[] args) { Runnable1 runnable1 = new Runnable1(); new Thread(runnable1).start(); }}
通过实现Runnable接口定义一个子任务,然后交给Thread去执行。使用这种方法只能使用Runnable作为Thread的参数然后使用start()方法来创建一个线程,同样,如果直接调用Runnable的run()方法的话,当前进程中执行了方法,并不会创建线程。
实现Callable,创建带返回值的线程
创建线程类
import java.util.Date;import java.util.concurrent.Callable;public class Callable1 implements Callable
使用线程池创建线程
import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class CallableTest1 { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println(">>> 程序开始执行 >>>"); Date date1 = new Date(); int tasksize = 5; // 创建一个线程池 ExecutorService threadPool = Executors.newFixedThreadPool(tasksize); // 创建有多个返回值的任务 Listlist = new ArrayList (); for (int i = 0; i < tasksize; i++) { Callable1 c = new Callable1("task" + i); // 执行任务并获取Future对象 Future f = threadPool.submit(c); list.add(f); } // 关闭线程池 threadPool.shutdown(); // 获取所有运行结果 System.out.println(">>> 获取运行结果 >>>"); for (Future f : list) { System.out.println(">>> " + f.get().toString()); } Date date2 = new Date(); System.out.println(">>> 程序运行结束 >>> 运行时间: " + (date2.getTime() - date1.getTime()) + "ms"); }}
实现Callable接口,相当于实现Runable接口的方式,方法可以有返回值,而且可以抛出异常。但是执行的时候需要Future接口的支持来获取返回结果。