Java多线程

Thread多线程提供的方法

Thread提供的常用方法

说明

public void run()

线程的任务方法

public void start()

启动线程

public String getName()

获取当前线程的名称,线程名称默认是Thread-索引

public void setName(String name)

为线程设置名称

public static Thread currentThread()

获取当前执行的线程对象

public static void sleep(long time)

让当前执行的线程休眠多少毫秒后,再继续执行

public final void join()...

让调用当前这个方法的线程先执行完!

Thread提供的常见构造器

说明

public Thread(String name)

可以为当前线程指定名称

public Thread(Runnable target)

封装Runnable对象成为线程对象

public Thread(Runnable target, String name)

封装Runnable对象成为线程对象,并指定线程名称

一,什么是多线程

  • 线程其实是程序中的一条执行路径。
  • 多线程就是同时拥有多条执行流程-----------边喝水边看电视

二,创建线程的方式 

Java为开发者提供了一个类叫做Thread,此类的对象用来表示线程

通过thread,Java虚拟机允许应用程序同时运行多个执行线程


1,创建线程------方式1(不建议)通过继承Thread类

  • 定义一个子类继承Thread类,并重写run方法

    • public class MyThread extends Thread{
          // 2、必须重写Thread类的run方法
          @Override
          public void run() {
              // 描述线程的执行任务。
              for (int i = 1; i <= 5; i++) {
                  System.out.println("子线程MyThread输出:" + i);
              }
          }
      }
  • 创建Thread的子类对象,创建一个Thread对象代表一个线程
    • //在测试类中
      Thread t = new MyThread();
  • 调用start方法启动线程,启动线程后会自动执行run方法中的代码
    • t.start(); //main调用 t线程

2,创建线程----方式2 通过实现Runnable接口

  • 先写一个Runnable接口的实现类,重写run方法(这里面就是线程要执行的代码)
  • /**
     * 1、定义一个任务类,实现Runnable接口
     */
    public class MyRunnable implements Runnable{
        // 2、重写runnable的run方法
        @Override
        public void run() {
            // 线程要执行的任务。
            for (int i = 1; i <= 5; i++) {
                System.out.println("子线程输出 ===》" + i);
            }
        }
    }
  • 再创建一个Runnable实现类的对象
    • 创建一个Thread对象,把Runnable实现类的对象传递给Thread
      • Runnable target = new MyRunnable();
    • 调用Thread对象的start()方法启动线程(启动后会自动执行Runnable里面的run方法)
      • // 4、把任务对象交给一个线程对象处理。
        //  public Thread(Runnable target)
        new Thread(target).start();
  • public class ThreadTest2 {
        public static void main(String[] args) {
            // 3、创建任务对象。
            Runnable target = new MyRunnable();
            // 4、把任务对象交给一个线程对象处理。
            //  public Thread(Runnable target)
            new Thread(target).start();
    
            for (int i = 1; i <= 5; i++) {
                System.out.println("主线程main输出 ===》" + i);
            }
        }
    }

3,使用匿名内部类创建线程

  • 可以创建Runnable的匿名内部类对象。
  • Java多线程_第1张图片
  • 再交给Thread线程对象。
  • 再调用线程对象的start()启动线程。
  • public class ThreadTest2_2 {
        public static void main(String[] args) {
            // 1、直接创建Runnable接口的匿名内部类形式(任务对象)
            Runnable target = new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i <= 5; i++) {
                        System.out.println("子线程1输出:" + i);
                    }
                }
            };
            new Thread(target).start();
    
            // 简化形式1:
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i <= 5; i++) {
                        System.out.println("子线程2输出:" + i);
                    }
                }
            }).start();
    
            // 简化形式2:
            new Thread(() -> {
                    for (int i = 1; i <= 5; i++) {
                        System.out.println("子线程3输出:" + i);
                    }
            }).start();
    
            for (int i = 1; i <= 5; i++) {
                System.out.println("主线程main输出:" + i);
            }
        }
    }

前三种方式都不可以返回run()方法执行的结果

 4,创建线程----方式3 实现Callable接口

  • 创建任务对象
    • 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
    • public Class MyCallable implements Callable<想要返回的数据类型>{
          private int n;
          //通过有参构造器的方式传入n的值
          public MyCallable(int n){
              this.n = n;
          }
          //重写call方法
          @Override
          public 返回的数据类型 call() throws Exception{
              //描述线程的任务,返回线程执行返回后的结果
              int sum = 0;
              for(int i =1;i
    • Callable类型的对象封装成FutureTask(线程任务对象)
      •  未来任务对象的作用?
        • 是一个任务对象,实现了Runnable对象.
        • 可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后的结果。
      • // 3、创建一个Callable的对象
        Callable call = new MyCallable(100);
        // 4、把Callable的对象封装成一个FutureTask对象(任务对象)
        FutureTask f1  = new FutureTask<>(call);

  • 把线程任务对象交给Thread对象。
  • 调用Thread对象的start方法启动线程。
    •  // 5、把任务对象交给一个Thread对象
      new Thread(f1).start();
  • 线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果。
    • f1是futureTask对象 未来任务对象
      String rs = f1.get();
      System.out.println(rs);

三,总结 

继承Thread的优缺点

  • 优点:编码简单
  • 缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。

实现Runnable接口的优缺点

  • 优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
  • 缺点:需要多一个Runnable对象

利用Callable接口、FutureTask类优缺点

  • 线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;
  • 可以在线程执行完毕后去获取线程执行的结果。
  • 编码复杂一点。

注意事项 

  1. 启动线程必须调用start方法,不是调用run方法,start方法是在Java虚拟机中注册线程
    1. 因为直接调用run方法会当成普通方法执行,此时还是相当于单线程执行
    2. 只有调用start方法态势启动一个新的线程执行
  2. 不要把主线程任务放在启动子线程(start)之前

你可能感兴趣的:(java,开发语言)