线程介绍
线程是程序运行的基本执行单元.
使用线程的优点:
- 充分利用CPU资源。
- 简化编程模型。
- 简化异步事件的处理。
- 节约成本。
线程的实现方式
Java中线程的实现有三种方式,分别是继承Thread类、实现Runnable接口和实现Callable接口。
- 继承Thread类
继承Thread类是Java中比较常见,也是很基础的一种实现Java多线程的方式。实现的方式也比较简单,只要将需要实现多线程的Java类继承java.lang.Thread类即可。该类中覆盖run()方法,将完成线程真正功能的代码写入run()方法中,然后调用Thread类中的start()方法启动线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class MyThread extends Thread{ private String name; public MyThread(String name){ this.name = name; } @Override public void run() { Thread.currentThread().setName(name); System.out.println("I am Thread :" +name); } }
public class threadLearn { public static void main(String[] args) { MyThread thread1 = new MyThread("Thread1"); thread1.start(); } }
|
- 实现Runnable接口
在Java中,类的继承是单一的,即一个子类仅可以继承一个父类,但可以实现多个接口。通过一个类继承Thread类来实现一个线程具有单继承的局限性,该子类不能再继承其他类,为了解决单继承的局限性,推荐通过实现Runnable()接口来实现一个线程。
使用Runnable()接口启动新线程的步骤如下:
(1)自定义类实现Runnable接口,并实现该接口的run()方法;
(2)用实现Runnable接口的对象作为参数实例化一个Thread对象;
(3)调用Thread类的start()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class MyRunnable implements Runnable { @Override public void run() { for (int i = 0;i < 10;i++) { System.out.println("一边听歌"); } } }
public class Test { public static void main(String[] args) { new Thread(new MyRunnable()).start(); for (int i = 0;i < 10;i++) { System.out.println("一边敲代码"); } } }
|
- 实现Callable接口
通过实现Callable接口,重写call()方法来实现一个线程。Callable接口是juc(java.util.concurrent)包下的一个泛型接口,只有一个call()方法。
Callable接口实现线程的步骤如下:
(1)自定义类实现Callable接口,并实现该接口的call()方法;
(2)创建实现Callable接口的自定义类对象;
(3)创建执行服务;
(4)提交执行;
(5)获取结果;
(6)关闭服务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class MyCallable implements Callable {
private String str;
public MyCallable(String str) { this.str = str; }
@Override public Boolean call() throws Exception { for (int i = 0;i < 10;i++) { System.out.println("一边"+str); } return true; } }
public class Test { public static void main(String[] args) throws InterruptedException, ExecutionException { MyCallable mc1 = new MyCallable("唱歌"); MyCallable mc2 = new MyCallable("敲代码"); ExecutorService ser = Executors.newFixedThreadPool(2); Future<Boolean> result1 = ser.submit(mc1); Future<Boolean> result2 = ser.submit(mc2); boolean r1 = result1.get(); boolean r2 = result2.get(); ser.shutdownNow(); System.out.println("线程1执行结果:" + r1); System.out.println("线程2执行结果:" + r2); } }
|
Callable接口与Runnable接口的功能类似,但提供了比Runnable更强大的功能,主要表现为以下三点:
Callable可以在任务结束后提供一个返回值,Runnable无法提供这个功能;
Callable接口中的call()方法可以抛出异常,而Runnable的run()方法不能抛出异常,必须在run()捕获;
运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,它提供了检查计算是否完成的方法。由于线程属于异步计算模型,因此无法从别的线程中得到函数的返回值,在这种情况下,就可以使用Future来监视目标线程调用call()方法的情况,当调用Future的get方法以获取结果时,当前线程就会阻塞,直到call()方法结束返回结果。