美国上市公司,专注Java培训22年

教程|Java多线程建立方式


继承Thread类创建线程类

public class Thread extends Object implements Runnable

1.定义Thread类的子类,并重写其run()方法

2.创建Thread子类的实例,即创建了线程对象

3.调用线程对象的start()方法启动线程

教程|Java多线程建立方式

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对象才是真正的线程对象。

教程|Java多线程建立方式

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

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对象

创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,再创建Callable实现类的实例

使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法

使用FutureTask类对象作为Thread对象的target创建并启动新线程

调用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){ ew Thread(task,"有返回值的线程").start(); } } try{ System.out.println("子线程的返回值"+task.get()); }catch(Exception e){ e.printStackTrace(); }

}

}

感谢大家阅读由java培训机构分享的“教程|Java多线程建立方式”希望对大家有所帮助,更多精彩内容请关注Java培训官网

免责声明:本文由小编转载自网络,旨在分享提供阅读,版权归原作者所有,如有侵权请联系我们进行删除


【免责声明】本文部分系转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,如涉及作品内容、版权和其它问题,请在30日内与我们联系,我们会予以重改或删除相关文章,以保证您的权益!

Java开发高端课程免费试学

大咖讲师+项目实战全面提升你的职场竞争力

  • 海量实战教程
  • 1V1答疑解惑
  • 行业动态分析
  • 大神学习路径图

相关推荐

更多
  • java语言中,char 类型变量是否能保存一个汉字?
    java语言中,char 类型变量是否能保存一个汉字?
    在 Java 语言中,可以使用 char 类型的变量来存储单个的字符,请问是否能用 char 类型的变量来存储一个汉字呢? 详情>>

    2015-10-15

  • 有史以来最牛的一张程序员职业路线图!
    有史以来最牛的一张程序员职业路线图!
    最近在琢磨程序员到底路在何方,经过不断的自虐和代入,终于在迷雾森林中得图一张,看之豁然开朗。独乐乐不如众乐乐,share了: 详情>>

    2018-05-22

  • java中变量和常量有什么区别?
    java中变量和常量有什么区别?
    在使用 Java 语言进行程序设计时,经常需要用到常量和变量来存储信息。请简单叙述变量和常量有什么区别? 详情>>

    2015-10-15

  • short 和 char 类型的取值范围各是多少?
    short 和 char 类型的取值范围各是多少?
    在使用 Java 语言进行程序设计时,经常需要使用 short 型和 char 型存储数值,请简述short 型和 char 型的取值范围各是多少? 详情>>

    2015-10-15

  • Java开班时间

    收起