软件编程
位置:首页>> 软件编程>> java编程>> java 多线程的三种构建方法

java 多线程的三种构建方法

作者:lqh  发布时间:2023-07-01 22:18:26 

标签: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)
  • 定义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<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();
   }
 }
}

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

来源:http://blog.csdn.net/gailyyelp/article/details/77969652

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com