java中的多线程实现方式
来源:互联网 发布:python创建临时文件夹 编辑:程序博客网 时间:2024/06/01 07:16
进程是资源分配的基本单位。
线程是CPU调度的基本单位。
在每一个进程上可以继续划分出若干个线程,那么线程的操作一定比进程更快,所以多线程的操作性能一定要超过多进程的操作,但是一定要在进程的基础之上进行划分。进程一旦消失,线程一定会消失。线程永远要依附于进程存在。
Java中对于多线程实现一定要有一个线程的主类,而线程的主类往往需要操作一些资源,但是这个多线程主类的实现是有一定要求的:
(1) 继承Thread父类;
(2) 实现Runnable接口(Callable接口)
1. 继承Thread类实现多线程
Thread类在java.lang包中,子类继承Thread类之后需要覆写Thread的run()方法,此方法就是线程的主方法。
所有的多线程一定是并发执行的,在同一个时间段(不是同一时刻)会有多个线程交替执行,为达到此目的,我们绝对不能直接去调用run方法,而是应该去调用Thread类中的start方法启动多线程。
由于线程的启动牵扯到系统的资源分配问题,所以具体的线程启动应该要根据不同的操作系统来具体的实现,而JVM相当于根据系统中定义的start0()方法来根据不同的操作系统进行该方法的实现,这样在多线程的层次上,start0()方法名不变,而不同的操作系统上有不同的实现。与接口的原理相似。
结论:只有Thread类的start()方法才能进行操作系统资源的分配,所以启动多线程的方式永远都是调用Thread类的start()方法实现。
2. 实现Runnable接口
继承Thread类会产生单继承的局限操作,所以最好的做法是利用接口解决问题,于是就可以使用Runnable来实现操作。
Runnable接口只有一个方法,是一个函数式接口,可以使用Lamda表达式完成。
如果想启动多线程,依靠的只能是Thread类中的start()方法,在此之前继承Thread类可以将start()继承下来直接使用,但是现在实现的是Runnable接口,所以此方法没有了。
在Thread类的构造方法中,有一个Thread(Runnable target)构造方法。
很多时候为了实现方便,可能直接使用匿名内部类或者Lamda实现代码。
匿名内部类:
new Thread(new Runnable(){
@Override
public void run() {
//方法体
for (inti = 0;i < 10;i++) {
System.out.println("i="+i);
}
}
}).start();
Lamda表达式实现:
new Thread(()->{
//方法体
for (inti = 0;i < 10;i++) {
System.out.println("i="+i);
}
}).start();
只要给出的是函数式接口,基本上就可以使用Lamda表达式或者是方法引用。
3. 两种实现比较
线程的两种实现模式:继承Thread类、实现Runnable接口,这两种模式本质上来讲,一定实现Runnable接口,使用Runnable接口实现可以避免单继承的局限,除了使用原则之外,还需要清楚两种方式的联系。
Thread类的定义结构:public class Thread extends Object implements Runnable,Thread类实现了Runnable接口。
Thread主要干两件事:(1)操作系统的资源分配;(2)调用我们自己实现的MyThread中的run()方法。
MyThread只是实现了线程开发的要求。
客户调用的是start()方法,而Thread调用MyThread类的run()方法,代码操作中使用的是一个代理模式的结构,如下图所示;但是与传统代理设计有些差别,如果按照传统代理设计模式来讲,如果要启动线程,理论上应该是run()方法,但实质上调用的start()方法,名称不符合,之所以会这样,主要是因为设计模式是长期发展后的产物。
除了以上的继承关联之外,还有一点区别:Runnable接口实现的多线程要比Thread类实现的多线程更方便的表示出数据共享的概念。示例如下:
(1)Thread类继承实现
classThreadTicketextends Thread{
private int ticket = 5;
@Override
public void run() {
for (inti = 0;i < 10;i++) {
if(this.ticket > 0){
System.out.println("卖票:ticket ="+this.ticket--);
}
}
}
}
public static void main(String[] args) {
ThreadTicket mt1 = new ThreadTicket();
ThreadTicket mt2 = new ThreadTicket();
ThreadTicket mt3 = new ThreadTicket();
mt1.start();
mt2.start();
mt3.start();
}
从输出结果可以看到,这个程序卖了很多假票,他们各自卖着各自的票,也就是每个线程各自占着各自的票数,内存模型如下所示。
(2)Runnable接口实现
classRunnableTicketimplements Runnable{
private int ticket = 5;
@Override
public void run() {
for (inti = 0;i < 10;i++) {
if(this.ticket > 0){
System.out.println("卖票:ticket ="+this.ticket--);
}
}
}
}
public static void main(String[] args) {
ThreadTicket mt = newThreadTicket();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
从输出结果可以看到,此程序没有卖假票。它们三个线程都占着同一个引用,其内存模型如下。
(3)面试题:请解释多线程两种实现方式的区别?请分别用代码验证。
a.多线程需要一个线程主类,这个类一定要么继承Thread类,要么实现Runnable接口。
b.使用Runnable接口可以比Thread类更好的实现数据共享的操作,并且利用Runnable接口可以避免单继承的局限。(代码验证如上所示)
4. 实现Callable接口
从jdk1.5之后,对于多线程的实现多了一个Callable接口,这个接口比Runnable接口唯一强大的地方在于它可以返回执行结果。此接口定义在java.util.concurrent中,是一个函数式接口,同时此接口使用了泛型,public V call() throws Exception,泛型即是返回值类型。
启动多线程需要调用start()方法,但是Thread类中没有提供接收Callable接口对象的操作。所以现在的问题是如何启动多线程?
在java.util.concurrent.FutureTask<V>类中的构造方法FutureTask(Callable<V> callable)中可以接收Callable,而FutureTask实现了RunnableFuture接口,然后RunnableFuture同时继承了Future(Future中有一个get()方法即拿到线程执行结果)和Runnable接口。FutureTask可以接收Callable接口对象,而实际上就相当于Runnable接口对象。其结构如下图所示。
采用Callable接口实现多线程示例如下:
classCallableThreadimplements Callable<String>{
private int ticket = 5;
@Override
public String call()throws Exception {
for (inti = 0;i < 10;i++) {
if(this.ticket > 0){
System.out.println("卖票:ticket ="+this.ticket--);
}
}
return"票卖完了!";
}
}
public static void main(String[] args) throws Exception {
Callable<String> cal = new CallableThread();
//取得执行结果
FutureTask<String> task = new FutureTask<String>(cal);
Thread thread = new Thread(task);
thread.start();
//取得主方法返回值
System.out.println(task.get());
}
对于线程的第三种实现方式没有特别要求,主要还是使用Runnable接口实现。
- Java中的多线程实现方式
- java中的多线程实现方式
- Java中的两种多线程实现方式
- Java多线程:实现方式
- JAVA多线程实现方式
- JAVA多线程实现方式
- JAVA多线程实现方式
- java多线程实现方式
- java多线程实现方式
- 【Java】多线程实现方式
- JAVA多线程实现方式
- Java 多线程--实现方式
- java多线程实现方式
- 实现java多线程方式
- JAVA多线程实现方式
- Java多线程实现方式
- JAVA多线程实现Runnable方式
- java实现多线程的方式
- Ubuntu16.04+CUDA8.0+GTX960M安装
- 修改SQLServer的sa密码
- Entity Framework Core 数据迁移
- flask中设置和获取cookie
- 写博客
- java中的多线程实现方式
- java 动态绑定
- poj 2386 Lake counting
- 不同的子序列-LintCode
- Activity生命周期:onCreate onStart onResume onPause onStop onDestory (1) 启动Activity: onCreate onStart onR
- 文字块自动换行
- 【技术干货】阿里云构建千万级别架构演变之路
- 虚拟现实到底是什么?
- React学习(五)this.props.children