四种方式实现多线程
-
继承 Thread 类创建线程
public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start();
-
实现Runnable接口创建线程
public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } } MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start();
-
实现Callable接口通过FutureTask包装器来创建Thread线程
public class SomeCallable<V> extends OtherClass implements Callable<V> { @Override public V call() throws Exception { // TODO Auto-generated method stub return null; } } Callable<V> oneCallable = new SomeCallable<V>(); FutureTask<V> oneTask = new FutureTask<V>(oneCallable); Thread oneThread = new Thread(oneTask); oneThread.start();
-
使用ExecutorService、Callable、Future实现有返回结果的线程
import java.util.concurrent.*; import java.util.Date; import java.util.List; import java.util.ArrayList; public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("----程序开始运行----"); Date date1 = new Date(); int taskSize = 5; ExecutorService pool = Executors.newFixedThreadPool(taskSize); List <Future> list = new ArrayList <Future>(); for (int i = 0; i < taskSize; i++) { Callable c = new MyCallable(i + " "); Future f = pool.submit(c); list.add(f); } pool.shutdown(); for (Future f : list) { System.out.println(">>>" + f.get().toString()); } Date date2 = new Date(); System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】"); } } class MyCallable implements Callable <Object> { private String taskNum; MyCallable(String taskNum) { this.taskNum = taskNum; } public Object call() throws Exception { System.out.println(">>>" + taskNum + "任务启动"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "任务终止"); return taskNum + "任务返回运行结果, 当前任务时间【" + time + "毫秒】"; } }
多线程相关知识
-
Runnable 和 Callable 的区别?
-
主要区别:
- Runnable 接口 run 方法无返回值;
- Callable 接口 call 方法有返回值,支持泛型。
-
异常处理:
-
Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;
-
Callable 接口 call 方法允许抛出异常,可以获取异常信息。
-
-
运行时异常通常是由程序逻辑错误引起的,例如除零操作、数组越界、空指针引用等。
换言之,Runable 比较保守,啥也没有。
- 如何启动一个新线程、调用 start 和 run 方法的区别?
- 调用 run 方法不开启线程,仅是对象调用方法。
- 调用 start 方法开启线程,并让 JVM 调用 run 方法在开启的线程中执行。调用 start 方法可以启动线程,并使得线程进入就绪状态,而 run 方法只是 thread 的一 个普通方法,还是在主线程中执行。
- 线程相关的基本方法?
- wait:线程进入 waiting 状态,释放对象锁。
- sleep:线程进入 TIMED-WATING 状态,不释放对象锁。
- yield:线程让出 CPU 执行时间片。
- join:等待其他线程终止。
- interrupt:中断一个线程。
- 不会直接停止线程的执行,而是设置了中断标志位。
- notify:唤醒在此对象监视器上等待的单个线程。
- notifyAll:唤醒在此对象监视器上等待的所有线程。
- wait() 和 sleep() 的区别?
- 来自不同的类:wait() 来自 Object 类;sleep() 来自 Thread 类。
- 关于锁的释放:wait() 在等待的过程中会释放锁;sleep() 在等待的过程中不会释放锁。
- 使用的范围:wait() 必须在同步代码块中使用;sleep() 可以在任何地方使用。
- 同步代码块:同步代码块通过关键字
synchronized
来定义,将一段代码包装在同步块中,以确保在同一时刻只有一个线程可以执行该代码块。
- 同步代码块:同步代码块通过关键字
- 是否需要捕获异常:wait() 不需要捕获异常;sleep() 需要捕获异常。
- 多线程原理
- 多线程是通过并发的方式进行。在某个时间点上,CPU 只能执行一个程序,即同一时间只能运行一个进程。CPU 在多个进程之间切换执行,每个线程执行一段时间。
- 多线程技术主要解决处理器单元内多个线程执行的问题,提高处理器单元的吞吐能力。