Java:多线程,分别用Thread、Runnable、Callable实现线程
并发性(concurrency)和并行性(parallel)是两个概念,并行是指在同一时刻,有多条指令在多个处理器上同时执行;并发指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得宏观上具有多个进程同时执行的效果。
多线程编程优点:
- 进程之间不能共享内存,但线程之间共享内存非常容易。
- 系统创建线程所分配的资源相对创建进程而言,代价非常小。
Java中实现线程的方式目前有三种:
一:继承Thread类创建线程类
package com.clzhang.sample.thread; // 通过继承Thread类来创建线程类 public class ThreadByExtends extends Thread { private int i; @Override public void run() { // 当线程类继承Thread类时,直接使用this即可获取当前线程句柄。 // 因此可以直接调用getName()方法返回当前线程的名称。 System.out.println("当前线程名称是:" + getName()); for (; i < 5; i++) { System.out.println(getName() + ":" + i); try { // 保证让别的线程也有执行的机会 Thread.sleep(10); } catch (InterruptedException e) { } } } public static void main(String[] args) { // 静态方法没有this,只能通过Thread.currentThread获取当前线程句柄 System.out.println(Thread.currentThread().getName()); // 创建、并启动第一条线程 new ThreadByExtends().start(); // 创建、并启动第二条线程 new ThreadByExtends().start(); } }
输出:
main
当前线程名称是:Thread-0
Thread-0:0
当前线程名称是:Thread-1
Thread-1:0
Thread-0:1
Thread-1:1
Thread-1:2
Thread-0:2
Thread-1:3
Thread-0:3
Thread-0:4
Thread-1:4
二:实现Runnable接口创建线程类
package com.clzhang.sample.thread; /** * 通过实现Runnable接口来创建线程类 * 1.Runnable非常适合多个相同线程来处理同一份资源的情况 * 2.Runnable可以避免由于Java的单继承机制带来的局限 * 3.如果想获取当前线程句柄,只能用Thread.currentThread()方法 */ public class ThreadByRunnable implements Runnable { private int i; @Override public void run() { System.out.println("当前线程名称是:" + Thread.currentThread().getName()); for (; i < 5; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); try { // 因为sleep是静态方法,所以不需要通过Thread.currentThread()方法获取当前线程句柄 Thread.sleep(10); } catch (InterruptedException e) { } } } public static void main(String[] args) { ThreadByRunnable st = new ThreadByRunnable(); new Thread(st, "新线程1").start(); new Thread(st, "新线程2").start(); } }
输出:
当前线程名称是:新线程1
当前线程名称是:新线程2
新线程2:0
新线程1:0
新线程2:2
新线程1:2
新线程2:3
新线程1:4
三:使用Calable和Future创建具备返回值的线程
package com.clzhang.sample.thread; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; // 实现Callable接口来实现线程 public class ThreadByCallable implements Callable<Integer> { @Override public Integer call() { System.out.println("当前线程名称是:" + Thread.currentThread().getName()); int i = 0; for (; i < 5; i++) { System.out.println("循环变量i的值:" + i); } // call()方法有返回值 return i; } public static void main(String[] args) { ThreadByCallable rt = new ThreadByCallable(); // 使用FutureTask来包装Callable对象 FutureTask<Integer> task = new FutureTask<Integer>(rt); new Thread(task, "有返回值的线程").start(); try { // 获取线程返回值 System.out.println("子线程的返回值:" + task.get()); } catch (Exception ex) { ex.printStackTrace(); } } }
输出:
当前线程名称是:有返回值的线程
循环变量i的值:0
循环变量i的值:1
循环变量i的值:2
循环变量i的值:3
循环变量i的值:4
子线程的返回值:5
总结
用Runnable与Callable接口的方式创建多线程的特点:
- 线程类只是实现了Runnable接口或Callable接口,还可以继承其它类。
- 在这种方式下,多个线程可以共享一个target对象,所以非常适合多个线程来处理同一份资源情况。
- 如果需要访问当前线程,需要使用Thread.currentThread方法。
- Callable接口与Runnable接口相比,只是Callable接口可以返回值而已。
用Thread类的方式创建多线程的特点:
- 因为线程已经继承Thread类,所以不可以再继承其它类。
- 如果需要访问当前线程,直接使用this即可。