壹影博客.
我在下午4点钟开始想你
Java多线程的三种实现方式与Thread常用API
  • 2023-4-29日
  • 0评论
  • 7244围观

Java多线程的三种实现方式与Thread常用API

一、继承Thread类的方式进行实现

实现步骤:
 1.自己定义一个类继承Thread
 2.重写Run方法
 3.创建子类的对象并启动线程

public class Demo {
  /**
   * 多线程的第一种启动方式:
   * 1.自己定义一个类继承Thread
   * 2.重写Run方法
   * 3.创建子类的对象并启动线程
   */
  public static void main(String[] args) {
    Case case1=new Case();//创建对象1
    Case case2=new Case();//创建对象2
    case1.setName("线程1");//为线程取名字
    case2.setName("线程2");//为线程取名字

    case1.start();//3.启动线程1
    case2.start();//3.启动线程2
  }

  //1.定义Case类继承Thread
  public static class Case extends Thread{
    @Override
    //2.重写run方法
    public void run() {
      //getName()为获取当前线程名称
      for (int i = 0; i < 100; i++) {
        System.out.println(getName()+"实现"+i);
      }
    }
  }
}

★该方法使用Lambda表达式进行简化

//该实现可以用Lambda表达式进行简化 如下

new Thread(()->{
  for (int i = 0; i < 100; i++) {
      System.out.println("线程1实现"+i);
  }
}).start();

new Thread(()->{
  for (int i = 0; i < 100; i++) {
      System.out.println("线程2实现"+i);
  }
}).start();

二、实现Runnable接口的方式进行实现

实现步骤:
1.自己定义一个类实现Runnalble接口
2.重写run方法
3.创建一个Thread类对象,并开启线程

public class Demo2 {
  /**
   * 多线程第二种启动方式
   * 1.自己定义一个类实现Runnalble接口
   * 2.重写run方法
   * 3.创建一个Thread类对象,并开启线程
   */
  public static void main(String[] args) {
   //创建Case对象,表示多线程要执行的任务
    Case case1=new Case();

    //3.创建线程(Thread)对象
    Thread t1=new Thread(case1,"线程1");
    Thread t2=new Thread(case1,"线程2");
    t1.start();//启动线程1
    t2.start();//启动线程2
  }
    
  //1.新建一个类实现Runnable接口
  public static class Case implements Runnable{
    @Override
    //2.重写run方法
    public void run() {
      //获取当前线程的名字
      String name=Thread.currentThread().getName();
      for (int i = 0; i < 100; i++) {
           System.out.println(name+"实现"+i);
      }
    }
  }
}

★该方法使用Lambda表达式进行简化

//该实现可以用Lambda表达式进行简化 如下

// 通过Lambda表达式创建匿名的Runnable对象,定义线程任务
Runnable task = () -> {
    //获取当前线程的名字
    String name=Thread.currentThread().getName();
    for (int i = 0; i < 100; i++) {
        System.out.println(name+"实现"+i);
    }
};
// 创建Thread对象,将上面创建的Runnable对象作为参数传入
new Thread(task,"线程1").start();
new Thread(task,"线程2").start();

三、利用Callable接口和Future接口方式实现

特点:可以获取到多线程的执行结果
1.自己定义一个类实现Callable接口,并提供返回值类型(泛型的位置)
2.重写call()方法(是有返回值的,表示多线程运行的结果)
3.创建FutureTask对象(作用管理多线程的结果)
4.创建Thread类的对象,并启动(表示线程)

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo3 {
  /**
   * 多线程第三种启动方式
   * 特点:可以获取到多线程的执行结果
   * 1.自己定义一个类实现Callable接口,并提供返回值类型(泛型的位置)
   * 2.重写call()方法(是有返回值的,表示多线程运行的结果)
   * 3.创建FutureTask对象(作用管理多线程的结果)
   * 4.创建Thread类的对象,并启动(表示线程)
   */
  public static void main(String[] args) {
    //实例化我们定义的对象
    Case case1=new Case();
    //创建FutreTask对象(作用管理多线程的结果)
    //注意泛型的类型要一致
    FutureTask<String> ft=new FutureTask<>(case1);

     
    Thread t1=new Thread(ft,"线程");
    t1.start();//启动线程1

    //获取多线程运行的结果 记得要捕获一下异常
    try {
        //获取多线程运行结果并打印
        String result1= ft1.get();
        System.out.println(result1);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    } catch (ExecutionException e) {
        throw new RuntimeException(e);
    }
  }
  //自己定义一个类实现Callable接口
  //我这边用返回值设置为String
  public static class Case implements Callable<String> {
    @Override
    public String call() throws Exception {
        //求1~100之间的和
        int sum=0;
        for (int i = 1; i <=100 ; i++) {
            sum+=i;//子增加i
        }
        //返回当前线程的名称+最终求和结果
        return Thread.currentThread().getName()+":"+sum;
    }
  }
}

★该方法使用Lambda表达式进行简化

//该实现可以用Lambda表达式进行简化 如下
//
FutureTask<String> ft1=new FutureTask<>(()->{
  //求1~100之间的和
  int sum=0;
  for (int i = 1; i <=100 ; i++) {
      sum+=i;//子增加i
  }
  //返回当前线程的名称+最终求和结果
  return Thread.currentThread().getName()+":"+sum;
});

new Thread(ft1).start();
System.out.println(ft1);

★三种实现方式的区别:

继承Thread类
优点:编程比较简单,可以直接使用Thread类中的方法
缺点:可以扩展性较差,不能再继承其他的类,无返回数据

②实现Runnable接口
优点:扩展性强,实现该接口的同时还可以继承其他的类
缺点:编程相对复杂,不能直接使用Thread类中的方法

③实现Callable接口
优点:扩展性强,实现该接口的同时还可以继承其他的类,可定义返回数据
缺点:编程相对复杂,不能直接使用Thread类中的方法

 

★Thread常用API

1.Thread(Runnable target): 创建一个新的线程对象,并指定它要执行的Runnable对象
2.start(): 启动一个线程
3.run(): 用于定义线程的主体,当线程被启动时,该方法自动调用
4.join([timeout]): 插入线程/插队线程

//join插入线程使用示例:
//不加插入线程的话main线程永远是执行在最前面的
//加入join插入线程后,main线程执行在后面了
public static void main(String[] args) {
  Thread t=new Thread(()->{
    for (int i = 0; i < 100; i++) {
      String name=Thread.currentThread().getName();
      System.out.println(name+":@"+i);
    }
  },"飞机");
  t.start();
  try {
      t.join();//将t线程插入到main线程前
  } catch (InterruptedException e) {
      throw new RuntimeException(e);
  }
  for (int i = 0; i < 10; i++) {
      System.out.println("min线程:"+i);
  }
}
5.isAlive(): 检查线程是否正在运行
6.currentThread(): 获取当前线程对象
7.yield(): 让出CPU控制权,让出线程/礼让线程
//yield礼让线程示例
public static void main(String[] args) {
  new Thread(() -> function(),"飞机").start();
  new Thread(() -> function(),"坦克").start();
}

public static void function(){
  String name=Thread.currentThread().getName();
  for (int i = 0; i < 100; i++) {
    System.out.println(name+":@" + i);
    Thread.yield();//出让线程
    //作用:使得两个线程执行尽可能的均匀
    //注意:不是绝对均匀,是尽可能的均匀
  }
}
8.sleep(long millis): 使当前线程休眠指定的毫秒数
9.interrupt(): 中断该线程的阻塞状态
10.setPriority(int priority): 设置线程的优先级 可设置1-10(默认为5)
11.getPriority(): 获取线程优先级
12.setDaemon(): 设置为守护线程(备胎模式)
//守护线程 示例
Thread t1 = new Thread(() -> {
  for (int i = 0; i < 10; i++) {
      System.out.println("女神:@" + i);
  }
});
Thread t2 = new Thread(() -> {
  for (int i = 0; i < 100; i++) {
      System.out.println("备胎:@" + i);
  }
});
t2.setDaemon(true);//设置为守护模式
//守护没有设置Daemon的线程,当没有设置Daemon的线程结束后
//设置了Daemon的线程运行一段后,自行结束

t1.start();
t2.start();
13.getState(): 获取线程的状态,如NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED
14.wait(): 使当前线程等待,直到其他线程调用notify()或者notifyAll()方法唤醒它。
15.notify(): 唤醒一个等待中的线程
16.notifyAll(): 唤醒所有等待中的线程

发表评论

渝ICP备19011465号 | 渝ICP备19011465号-1