栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java  多线程的三种构建方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java  多线程的三种构建方法

java  多线程的三种构建方法

继承Thread类创建线程类

public class Thread extends Object implements Runnable
  1. 定义Thread类的子类,并重写其run()方法
  2. 创建Thread子类的实例,即创建了线程对象
  3. 调用线程对象的start()方法启动线程
public class FirstThread extends Thread {
  public void run(){
    for(int i=0;i<100;i++){
      
      System.out.println(this.getName()+" "+i);
    }
  }

  public static void main(String[] args) {
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
      if(i==20){
 new FirstThread().start();
 new FirstThread().start();
      }
    }
  }

}

Thread类已经继承了Object

Object类创建了name选项 并且有其getName(),setName()方法

在继承Thread的类里面使用时只需要用this引用

上面两个副线程和主线程随机切换,又因为使用的是继承Thread的类所以两个副线程不能共享资源

start()方法调用后并不是立即执行多线程代码,而是使得该线程编程可运行状态,什么时候运行是由操作系统决定的

实现Runnable接口创建线程类

public Thread() 
public Thread(Runnable target) 
public Thread(Runnable target,String name)
  • 定义Runnable接口的实现类,并重写该接口的run()方法
  • 创建Runnable实现类的实例,并以此作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
public class SecondThread implements Runnable {
  public void run(){
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
    }
  }

  public static void main(String[] args) {
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);

      if(i==20){
 SecondThread st=new SecondThread();
 //通过new Thread(target,name)创建线程
 new Thread(st,"新线程1").start();
 new Thread(st,"新线程2").start();
      }
    }
  }
}

上面的结果是两个副线程和主线程随机切换,但是并没有共享资源,因为他们根本没有能用来共享的资源。

start()方法调用后并不是立即执行多线程代码,而是使得该线程编程可运行状态,什么时候运行是由操作系统决定的
继承Thread类和创建Runnable接口的共享资源详解

在只有可以用来共享的资源时候,也就是同用一个实例化对象。两个创建方式在共享资源时才会有所区别,否则它们都不会共享资源共享资源通常用private static 修饰符来修饰。

class Thread1 extends Thread{ 
  private int count=5; 
  private String name; 
  public Thread1(String name) { 
    this.name=name; 
  } 
  public void run() { 
    for (int i = 0; i < 5; i++) { 
      System.out.println(name + "运行 count= " + count--); 
      try { 
 sleep((int) Math.random() * 10); 
      } catch (InterruptedException e) { 
 e.printStackTrace(); 
      } 
    } 

  } 
} 

public class Main { 

  public static void main(String[] args) { 
    Thread1 mTh1=new Thread1("A"); 
    Thread1 mTh2=new Thread1("B"); 
    mTh1.start(); 
    mTh2.start(); 

  } 

} 

B运行 count= 5 
A运行 count= 5 
B运行 count= 4 
B运行 count= 3 
B运行 count= 2 
B运行 count= 1 
A运行 count= 4 
A运行 count= 3 
A运行 count= 2 
A运行 count= 1

正是因为有了private int count=5;一句才有了共享资源,但这是继承Thread类的子类,并不能共享资源

class Thread2 implements Runnable{ 
  private int count=15; 
  public void run() { 
     for (int i = 0; i < 5; i++) { 
System.out.println(Thread.currentThread().getName() + "运行 count= " + count--); 
 try { 
   Thread.sleep((int) Math.random() * 10); 
 } catch (InterruptedException e) { 
   e.printStackTrace(); 
 } 
      } 

  } 

} 
public class Main { 

  public static void main(String[] args) { 

    Thread2 my = new Thread2(); 
      new Thread(my, "C").start();//同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常   
      new Thread(my, "D").start(); 
      new Thread(my, "E").start(); 
  } 

} 

C运行 count= 15 
D运行 count= 14 
E运行 count= 13 
D运行 count= 12 
D运行 count= 10 
D运行 count= 9 
D运行 count= 8 
C运行 count= 11 
E运行 count= 12 
C运行 count= 7 
E运行 count= 6 
C运行 count= 5 
E运行 count= 4 
C运行 count= 3 
E运行 count= 2

同样的正是因为有了private int count=15这个共同的实例化对象,实现Runnable的类才可以共享资源

那么为什么继承Thread类的子类实现Runable接口的类在共享资源时有区别呢?

因为Java中只能支持单继承,单继承特点意味着只能有一个子类去继承 而Runnabl接口后可以跟好多类,便可以进行多个线程共享一个资源的操作

使用Callable和Future创建线程

Callable怎么看起来都像Runnable接口的增强版,Callable有一个call()方法相当于Runnable的run()方法,但是功能却更加强大:

call()方法可以有返回值
call()方法可以声明抛出异常

Callable接口有泛型限制,Callable接口里的泛型形参类型与call()方法的返回值类型相同。 而且Callable接口是函数式接口,因此可使用Lambda表达式创建Callable对象 Runnable接口也是函数式接口,因此也可以使用Lambda表达式创建Runnable对象

  1. 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,再创建Callable实现类的实例
  2. 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法
  3. 使用FutureTask类对象作为Thread对象的target创建并启动新线程
  4. 调用FutureTask对象的get()方法来获得子线程结束后的返回值
public class ThirdThread implements Callable {
  public Integer call(){
    int i=0;
    for(;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
    }
    return i;
  }

  public static void main(String[] args){
    ThirdThread tt=new ThirdThread();
    FutureTask task=new FutureTask<>(tt);
    Thread t=new Thread(task,"有返回值的线程");
    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+" "+i);
      if(i==20){
 t.start();
      }
    }
    try{
      System.out.println("返回值是:"+task.get());
    }catch(Exception e){
      e.printStackTrace();
    }
  }
}

使用Lambda表达式的Callable和Future创建的线程

public class ThirdThread{
  public static void main(String[] args){
    ThirdThread tt=new ThirdThread();
    //先使用Lambda表达式创建Callable对象
    //使用FutureTask封装Callable对象
    FutureTask task=new FutureTask((Callable)()->{
      int i=0;
      for(;i<100;i++){
 System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
      }
      return i;
    });

    for(int i=0;i<100;i++){
      System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
      if(i==20){
 new Thread(task,"有返回值的线程").start();
      }
    }
    try{
      System.out.println("子线程的返回值"+task.get());
    }catch(Exception e){
      e.printStackTrace();
    }
  }
}

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/144260.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号