从设计的角度讨论Java中线程的两种创建方式-阿里云开发者社区

开发者社区> 一路漫漫> 正文

从设计的角度讨论Java中线程的两种创建方式

简介: Java中的多线程让我们的程序可以同时运行多个任务,即使我们的CPU是单核的。当然我们都明白这种情况下的同时运行,并不是真正的同时运行,而是JVM中的线程调度器根据时间片轮转的方式快速的在不同线程间的切换。
+关注继续查看

Java中的多线程让我们的程序可以同时运行多个任务,即使我们的CPU是单核的。当然我们都明白这种情况下的同时运行,并不是真正的同时运行,而是JVM中的线程调度器根据时间片轮转的方式快速的在不同线程间的切换。线程调度器让JVM一会运行这个线程,一会运行那个线程,切换的速度很快便我们产生了这些线程好像同时运行的假象。

线程的创建方式有两种,这两种方式究竟有什么不同?性能有什么差异?为什么要设计两种方式呢?带着这些疑问,我们首先回顾一下线程的两种创建方式。

第一种方式,通过实现Runnable接口来创建一个线程:

public class StudyThread{
	public static void main(String[] args){
		MyRunnable myRunnable = new MyRunnable();
		Thread thread = new Thread(myRunnable);
		thread.start();
		
	}
}

class MyRunnable implements Runnable{
	public void run(){
		System.out.println("第一种创建方式");
	}
}


第二种方式,通过继承Thread类来创建一个线程:

public class StudyThreadTwo{
	public static void main(String[] args){
		MyThread myThread = new MyThread();
		myThread.start();
	}
}

class MyThread extends Thread{
	public void run(){
		System.out.println("第二种启动方式");	
	}	
}


通过这两种方式,都能正常创建一个新的线程,性能方面我觉得应该没有多大差异,我们来从设计的角度看一下它们究竟有什么不同。

第一种创建方式是最经常被使用的创建方式。它创建一个线程,需要两个相关类,一个Java提供的Thread类,另一个是要我们自己实现的:实现Runnable接口,并实现run方法。我们要做的就是创建一个Thread对象,在创建时需要一个Runnable类型的参数是需要我们自己实现的。在实际中我们通常使用匿名内部类来实现这种方式,具体如下:

public class StudyThread{
	public static void main(String[] args){
		Thread thread = new Thread(new Runnable(){
			public void run(){
				System.out.println("使用匿名内部类创建线程");
			}
		});
		thread.start();
	}
}

第二种创建方式只需要一个类,就是我们继承自Thread类,然后重写run方法。这种创建方式相比第一种仿佛更简单。实际上这种简单是有代价的,如果我们从设计的角度(设计原则、设计模式)来考虑的话,就会明白我们为什么在实际中很少用这种方式。

根据设计原则中的单一职责原则,我们的类应该仅实现一类功能,应该有且仅有一个原因引起类的变更,应该让界面显示的类只负责界面显示,数据处理只负责数据处理,控制的只负责控制,最合适的例子就是MVC这种复合设计模式。我们再回到上面的分析,为了便于理解,我们可以将Thread类看做一个工人(a worker),Runnable(中的run方法)就是这个工人的工作(work),在第一种创建方式中,工人是工人,工作是工作(松耦合),工作(Runnable)的变更不会影响到工人(Thread);而在第二种创建方式中,工人与工作绑定死了(紧耦合),工作一变,工人也跟着变,这种牵一发而动全身的编程方式,在简单的工程中还好说,如果在一个及其庞大的项目中的话,如果你的一个地方的修改要引起整个系统的更改的话,那你与你的项目会一起崩溃的。

既然第二种相比第一种有如此弊端,为什么还要设计第一种呢?我觉得我们可以从继承的角度来理解。继承可以让子类自动共享父类的数据和方法,并允许子类添加新的数据或者方法。我们有时就是需要一个工作与工人绑定的,并如果被大量使用的,第二种方式就有优点了。不知道这种理解方式合适与否,欢迎大家积极参与讨论。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)
原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七:   程序包的创建与应用(聪明在于学习,天才在于积累!) ——通过知识共享树立个人品牌。
1210 0
【spring bean】bean的配置和创建方式
---恢复内容开始---   项目结构如下:   lib如下:       1.首先建立SayHell.java接口 1 package com.it.sxd; 2 3 public interface SayHell { 4 public void sayHello(); 5 } View Code 2.
721 0
LintCode 题解丨面试真题:两数之和 III-数据结构设计
LintCode 题解丨面试真题:两数之和 III-数据结构设计
160 0
c# 纯代码方式创建快捷方式
原文:c# 纯代码方式创建快捷方式 using System; using System.Collections.Generic; using System.Text; using Microsoft.
563 0
javascript中创建对象的几种方式
原文:javascript中创建对象的几种方式 javascript中提供了通过Object构造函数或对象字面量方式来创建单个的对象,当我们想要创建很多对象的时候,简单的通过这两种方法就会产生大量的重复。
959 0
【Android NDK 开发】JNI 线程 ( JNI 线程创建 | 线程执行函数 | 非 JNI 方法获取 JNIEnv 与 Java 对象 | 线程获取 JNIEnv | 全局变量设置 )
【Android NDK 开发】JNI 线程 ( JNI 线程创建 | 线程执行函数 | 非 JNI 方法获取 JNIEnv 与 Java 对象 | 线程获取 JNIEnv | 全局变量设置 )
19 0
JVM源码分析之一个Java进程究竟能创建多少线程
##概述 虽然这篇文章的标题打着JVM源码分析的旗号,不过本文不仅仅从JVM源码角度来分析,更多的来自于Linux Kernel的源码分析,今天要说的是JVM里比较常见的一个问题 这个问题可能有几种表述 * 一个Java进程到底能创建多少线程? * 到底有哪些因素决定了能创建多少线程
5975 0
java多线程之:创建开启一个线程的开销
---->关于时间,创建线程使用是直接向系统申请资源的,这里调用系统函数进行分配资源的话耗时不好说。---->关于资源,Java线程的线程栈所占用的内存是在Java堆外的,所以是不受java程序控制的,只受系统资源限制,默认一个线程的线程栈大小是1M(当让这个可以通过设置-Xss属性设置,但是要注意栈溢出问题),但是,如果每个用户请求都新建线程的话,1024个用户光线程就占用了1个G的内存,如果系统比较大的话,一下子系统资源就不够用了,最后程序就崩溃了。
718 0
html5 getComputedStyle + resize 实现动态宽高度等比响应式页面设计
序:通常我们只能控制div的宽度 而不能控制高度,在响应式页面里 如果要这个div是正方形那么必须的用媒体查询在不同的分辨率下写死宽高度 今天突发奇想研究了个 用百分比来动态控制div的高度让其与宽度相同 成为一个正方形 甚至任何你想要比例 一,背景:目前移动端大多数图片或视频列表页面的显示,列出...
989 0
+关注
一路漫漫
爱做产品的程序猿
45
文章
1
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载