• 技术文章 >Java >java教程

    Java中使用三种构建多线程的方法分享

    黄舟黄舟2017-09-18 09:37:35原创678
    这篇文章主要介绍了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++){
          /*
           * Thread类已经继承了Object
           * Object类创建了name选项 并且有其getName(),setName()方法
           * 在继承Thread的类里面使用时只需要用this引用
          */
          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)


    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<Integer> {
      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<Integer> 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<Integer>对象
        //使用FutureTask封装Callable对象
        FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{
          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();
        }
      }
    }

    以上就是Java中使用三种构建多线程的方法分享的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:Java 线程 构建
    上一篇:Java中关于线程安全的基础概念解析 下一篇:Java中关于null的含义以及使用中要注意的事项
    20期PHP线上班

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• 一文带你认识Java栈和队列• 一文掌握Java8新特性Stream流的概念和使用• Java线程学习之并发编程知识点• 完全掌握Java中的抽象类和接口• Java中的set集合如何理解
    1/1

    PHP中文网