多线程(一)-两种创建线程的方式

打印 上一主题 下一主题

主题 778|帖子 778|积分 2334

大佬的理解->Java多线程(一)多线程基础
大佬的理解->Java多线程(二)常用的实现多线程的两种方式
1、继承Thread类

​        继承Thread必须重写run方法,(具体业务执行方法,需要执行的业务方法,定义在此方法中),注意此方法是线程启动后线程自动调用的;
案例
  1. public class MyThread extends Thread{
  2.     @Override
  3.     public void run() {
  4.         //线程执行的业务方法
  5.         System.out.println("子线程执行");
  6.         for (int i = 0;i < 5;i++){
  7.             System.out.println("--- 线程名---:"+Thread.currentThread().getName()+",序号:"+i);
  8.         }
  9.     }
  10.     public static void main(String[] args) {
  11.         //主线程
  12.         System.out.println("***主线程执行***");
  13.         System.out.println("***线程名***:"+Thread.currentThread().getName());
  14.         //创建一个线程并启动,只能通过主线程创建其他线程
  15.         MyThread thread1 = new MyThread();
  16.         MyThread thread2 = new MyThread();
  17.         //启动线程:start()方法(一旦启动,自动启动子线程,当前线程继续向下执行,不会等子线程)
  18.         thread1.start();
  19.         //启动多线程
  20.         //多线程并发执行:不是正真一样上的并行执行(肉眼感官是并行),而是通过cpu的调度算法,有序cpu执行极快,所以肉眼看起来是并行的;
  21.         thread2.start();
  22.         //调用run方法,不可以启动线程,就是对象的普通方法调用,等run方法执行结束,主线程才能继续执行
  23.         //thread1.run();
  24.         //thread2.run();
  25.         System.out.println("----主线程执行结束----");
  26.     }
  27. }
复制代码
运行结果
调用start()方法
  1. ***主线程执行***
  2. ***线程名***:main
  3. ----主线程执行结束----
  4. 子线程执行
  5. --- 线程名---:Thread-0,序号:0
  6. --- 线程名---:Thread-0,序号:1
  7. --- 线程名---:Thread-0,序号:2
  8. --- 线程名---:Thread-0,序号:3
  9. --- 线程名---:Thread-0,序号:4
  10. 子线程执行
  11. --- 线程名---:Thread-1,序号:0
  12. --- 线程名---:Thread-1,序号:1
  13. --- 线程名---:Thread-1,序号:2
  14. --- 线程名---:Thread-1,序号:3
  15. --- 线程名---:Thread-1,序号:4
复制代码
调用run()方法
  1. ***主线程执行***
  2. ***线程名***:main
  3. 子线程执行
  4. --- 线程名---:main,序号:0
  5. --- 线程名---:main,序号:1
  6. --- 线程名---:main,序号:2
  7. --- 线程名---:main,序号:3
  8. --- 线程名---:main,序号:4
  9. 子线程执行
  10. --- 线程名---:main,序号:0
  11. --- 线程名---:main,序号:1
  12. --- 线程名---:main,序号:2
  13. --- 线程名---:main,序号:3
  14. --- 线程名---:main,序号:4
  15. ----主线程执行结束----      //必须等子线程完成后才可以继续运行
复制代码
注意start()方法和run()方法的区别
start():启动线程start()方法(一旦启动,自动启动子线程,当前线程继续向下执行,不会等子线程);
run()  :调用run方法,不可以启动线程,只是对象的普通方法调用,等run方法执行结束,主线程才能继续执行;
2、实现Runnable接口

实现Runnable接口,也必须实现run方法;
案例
  1. public class MyRunnable implements Runnable{
  2.     private int num = 5;
  3.     @Override
  4.     public void run() {
  5.         //线程执行的业务方法
  6.         System.out.println("子线程执行");
  7.         for (int i = 0;i < 5 ;i++){
  8.             if(num>0){
  9.                 System.out.println("--- 线程名---:"+Thread.currentThread().getName()+",序号:"+num--);
  10.             }
  11.         }
  12.     }
  13.     public static void main(String[] args) {
  14.         //主线程
  15.         System.out.println("***主线程执行***");
  16.         System.out.println("***线程名***:"+Thread.currentThread().getName());
  17.         //创建一个子线程,并启动
  18.         MyRunnable runnable1 = new MyRunnable();
  19.         //实现Runnable接口方式创建的线程,不能自己启动,只能通过Thread类,将Runnable作为参数传入Thread类的构造方法中,
  20.         // 构造线程对象,才可以启动
  21.         Thread thread1 = new Thread(runnable1);
  22.         thread1.start();
  23.         //创建多线程 (如果传入的Runnable参数一样,可以共享资源)
  24.         Thread thread2 = new Thread(runnable1);
  25.         thread2.start();
  26.         System.out.println("----主线程执行结束----");
  27.     }
  28. }
复制代码
运行结果
  1. ***主线程执行***
  2. ***线程名***:main
  3. ----主线程执行结束----
  4. 子线程执行
  5. 子线程执行
  6. --- 线程名---:Thread-0,序号:5
  7. --- 线程名---:Thread-1,序号:4
  8. --- 线程名---:Thread-0,序号:3
  9. --- 线程名---:Thread-1,序号:2
  10. --- 线程名---:Thread-0,序号:1
复制代码
注意
如果传入的Runnable参数一样,可以共享资源;
3、比较两种创建线程的方式

继承Thread类

  • 编写简单,可直接操作线程
  • 适用于单继承
实现Runnable接口

  • 避免单继承局限性
  • 便于共享资源
4、实现Callable接口

4.1实现Callable接口调用的call方法

创建线程的方式三,实现Callable接口,线程自动调用的时call方法,不是run方法,jdk1.5后才提供;
4.2 FutureTask 类的继承关系

执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。
  1. //FutureTask<V> 是 RunnableFuture<V> 的实现类
  2. public class FutureTask<V> implements RunnableFuture<V> ;
  3. //RunnableFuture<V> 接口继承了 Runnable, Future<V>          //所以FutureTask最后需要放到Thread参数中,这里跟继承Runnable方法一样;
  4. public interface RunnableFuture<V> extends Runnable, Future<V> ;
复制代码
类图

4.3 案例
  1. public class MyCallable implements Callable<Integer>{
  2.     @Override
  3.     public Integer call() throws Exception {
  4.         System.out.println("***子线程执行***");
  5.         //执行线程处理方法
  6.         int sun = 0;
  7.         for (int i = 0; i < 5; i++) {
  8.             sun+=i;
  9.         }
  10.         return sun;
  11.     }
  12.     public static void main(String[] args) {
  13.         //主线程执行
  14.         System.out.println("---主线程执行---");
  15.         //创建子线程,不可以自己单独启动,必须借助FutureTask才可以,必须获取子线程执行结果
  16.         MyCallable callable = new MyCallable();
  17.         FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
  18.         //启动线程,只能借助Thread类
  19.         Thread thread = new Thread(futureTask);
  20.         thread.start();
  21.         //获取子线程的执行结果(必须要子线程执行结束,才可以获取结果)
  22.         try {
  23.             Integer resultSun = futureTask.get(); //接收返回值
  24.             System.out.println("五以内的数字之和:"+resultSun);
  25.         } catch (Exception e) {
  26.             e.printStackTrace();
  27.         }
  28.         System.out.println("---主线程结束---");
  29.     }
  30. }
复制代码
运行结果
  1. ---主线程执行---
  2. ***子线程执行***
  3. 五以内的数字之和:10  //接收到返回值
  4. ---主线程结束---
复制代码
4.4  Callable和Runnable的区别

1)所在包不同,Callable在java.util.concurrent包下,Runnable在java.lang包;
2)实现的接口方法不同:Callable是重写call方法,Runnable的重写run方法;
3)抛出异常处理不同:Callable是重写call方法,可以抛出异常,但是Runnable是重写run方法不可以抛出异        常,如果抛出线程直接中断;
4)返回值不同:实现Callable接口的线程,可以通过FutureTask获取返回值,但是是西安Runnable揭露的线程,无法获取返回值;

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表