多线程的三种建立方式

来源:互联网 发布:informix sql 语法 编辑:程序博客网 时间:2024/06/06 05:18

继承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();            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Thread类已经继承了Object 
Object类创建了name选项 并且有其getName(),setName()方法 
在继承Thread的类里面使用时只需要用this引用

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

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


实现Runnable接口创建线程类

public Thread() 
public Thread(Runnable target) 
public Thread(Runnable target,String name)

  1. 定义Runnable接口的实现类,并重写该接口的run()方法
  2. 创建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();            }        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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

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();      }  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

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();      }  }  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

使用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();        }    }}