基础结构:
在Java的Thread体系中,最基础的就是Runnable接口,它代表了一个线程功能的“契约”,或者是线程的功能在Java中的表述,因为线程不是哪个语言的特有,而是操作系统的特有,所以这里就给予一个中性的描述“此接口就是一个线程功能在Java中的表述”,请看它在Java中声明的结构:
public interface java.lang.Runnable {
public void run();
}
这类似Command设计模式,只提供一个方法抽象,代表所有的“命令”,这里也有这样的意思,也就是用这个接口就可以描述一个线程“想干什么”的问题,我们可以实现这个接口:
public class dosomethingThread implements Runnable {
@Override
public void run() {
System.out.println("do somethings");
}
}
这是一个正常的方式,还可以使用下面这样方式:
public class ThreadBasicDemo {
/**
* @param args
*/
public static void main(String[] args) {
Runnable runnableInterface = new Runnable() {
@Override
public void run() {
System.out.println("do somethings");
}
};
}
}
有了想让线程做什么事情的“核”,接下来就应该把这个“核”包裹在一个真正的线程中了,在Java中,线程是用Thread类表示的,这个类包装了与操作系统交互而管理线程的逻辑,我们不用知道!不过喜欢探索的家伙可能还是喜欢看一看咋回事!所以我这里列出一个Thread的Start方法在JDK实现片段(一个线程是Start方法启动的):
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0 || this != me)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private native void start0();
可以看到其注释中说明是JVM来创建线程的,而不同OS的JVM实现是具体与OS打交道的,那个native void start0()方法,没有实现体,是JVM实现的,就像是C#调用windows API一样,不过这里是调用JVM的"API".所以你必须知道创建线程和管理线程这事情是由JVM通信OS来实现的,是OS所特有的东西,和具体语言无关!当然也和平台无关,如.Net,Java,Python等等.
另外这个类直接从Runnable接口实现而来,所以这里需要澄清的是,它只是实现了run方法为一个空壳,里面没有具体功能,看一下它的构造函数:
可以看到具体干活的还是Runnable的实例,只是注入到Thread中而已,那么为什么Thread从Runnable实现,这就像一个适配器,一个默认的实现,我们可以直接重载Thread的run方法做一些事情(功能),而不必再用注入的方式使用它,而且从语义来讲,“功能的核”和“线程的壳“是在一起的,那么就会产生干不同活的Thread:
Java内建了很多具备不同功能的Thread类型(不仅有功能还是线程!)。
对于我们自己的功能线程,是使用继承覆盖还是接口注入的方式,完全取决于你。
public class ThreadBasicDemo {
/**
* @param args
*/
public static void main(String[] args) {
Runnable runnableInterface = new Runnable() {
@Override
public void run() {
System.out.println("do somethings");
}
};
Thread newThread=new Thread(runnableInterface);
newThread.start();
}
}
使一个线程在操作系统中创建出来,只需要调用Thread的start方法即可,它知道如何在操作系统中创建线程,确切的说是在当前进程中创建,另外这里还提供了一个抽象层,那就是不管你是什么操作系统(windows,unix,linux),不管这些OS创建线程的方式有什么不同,它都能自动处理,调用方不需要知道!。另外Executor也可以执行一个Runnable所代表的任务,后面的文章中会有讲。
上面是创建线程的两种方式,都在java.lang包中,另外你可能注意到在run方法中只是返回一个void,也就是说不支持返回某些结果,但是很多时候你希望返回一些结果,幸好Java 5.0提供了Callable接口(在java.util.concurrent包中),它的作用和Runnable接口一样,但是它允许返回结果,在Java中它被声明成:
public interface java.util.concurrent.Callable {
public java.lang.Object call() throws java.lang.Exception;
}
可以看到它与Runnable不同的地方就是可以返回结果(任何类型的),还可以抛出异常!
在使用方面,它不能与Thread联合直接使用,比如在构造函数中注入使用,因为如果等待一个结果的返回,就等于让主程序堵塞,所以它需要和Future一起配合使用,Future也是一个并发包中新类,代表了未来要”取“的结果:
Callable<Object> callableInterface=new Callable<Object>() {
@Override
public Object call() throws Exception {
System.out.println("do somethings");
return null;
}
};
此接口还使用了泛型,也就是说我们可以为其设定任何返回类型。
ExecutorService threadpool = Executors.newFixedThreadPool(2);
Future<Object> p = threadpool.submit(callableInterface);
之后就可以通过Future的get方法取得结果,get会等待最终得到的结果,可以看出这是一个异步模型,也就是说”提交“给ExecutorService之后,就可以放任不管了,不会使主程序堵塞。对于ExecutorService,我会在后面的文章中讲到。
状态控制:
所有的线程都有生命周期,其中要经历的状态有(可以通过getState方法来查询):
NEW
Thread已被创建,但其start() method尚未被调用。所有线程都会从这个状
开始 。
RUNNABLE
线程正在运行或在操作系统调度它时就可运行。
BLOCKED
因为线程在等待取得锁定以便进入同步方法或程序块,所以线程并未运行。
WAITING
线程因为调用了 Object.wait()或Thread.join()而未运行。
TIMED_WAITING
线程因为调用了 Thread.sleep()或加上逾时值来调用 Object.wait()
Thread.join()而未运行。
TERMINATED
线程已运行完毕。它的 run()已正常结束或通过抛出异常而结束。
你可能很奇怪,Object.wait是干什么的,这是Java在所有类型基类Object中封装的方法,也就是说不管你是什么类型都有这个方法,不光只有这一个方法,还有notify和notifyAll方法,干什么用的哪?
wait就是把当前对象所在线程设置到等待状态,直到另外一个线程调用那个线程的Notify或者notifyAll来”通知“前面提到的那个线程结束等待状态继续运行,这对于一个等着另一个的场景实现很有帮助,另外后面的文章还会介绍一个semaphore类似于信号量的东西,也可以更加简单的做这样的事情。
异常处理
当一个线程出现了异常时,线程进入终止状态,但是如何处理这个异常哪?
newThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread arg0, Throwable arg1) {
//do somethings
}
});
线程的优先级
线程可以以不同的优先级运行。 指定优先级的线程通常会在已无具较高优先级的线程等
待时才会运行。在运作线程优先级时,你可以使用这里的一些程序代码:
// 将线程优先级设定为低于一般标准
t.setPriority(Thread.NORM_PRIORITY-1);
// 将线程的优先级设定为低于当前线程
t.setPriority(Thread.currentThread().getPriority() - 1);
// 不需等待I/O的线程应该要明确地让出CPU,以让其他具有相同优先
// 级的线程有机会运行
Thread t = new Thread(new Runnable() {
public void run() {
for(int i = 0; i < data.length; i++) { // 逐一处理一组数据
process(data[i]); // 加以处理
if ((i % 10) == 0) // 但在每处理10个后,就暂
Thread.yield(); // 停以让其他线程运行
}
}
});
其中线程的yield方法起到一个复合作用,不像wait只是挂起当前线程,而是挂起当前线程,并通知其他线程开始运行。
Thread类的其他方法说明
stop():停止当前线程
sleep(..):让当前线程休眠一段时间
Thread.currentThread():得到当前线程
........
都比较简单,这里就不再描述和讲解了。下一篇将讲解线程的调度(全在java.util.concurrent包中,越来越进入到核心部分了)。
分享到:
相关推荐
Vue 3.0+Vite 2.0+Vue-Router4.0+Element-Plus+Echarts 5.0+Axios 开发的后台管理系统 Vue 3.0+Vite 2.0+Vue-Router4.0+Element-Plus+Echarts 5.0+Axios 开发的后台管理系统 Vue 3.0+Vite 2.0+Vue-Router4.0+...
dotnet-sdk-5.0.408-win-x64
dotnet-sdk-5.0.202-win-x64.exe
本文将详细介绍dotnet-sdk-5.0.400-linux-x64及其包含的组件,探讨其在跨平台开发中的重要性。 首先,"dotnet-sdk-5.0.400-linux-x64.tar.gz"是一个针对Linux x64架构的.NET SDK压缩包。这个版本5.0.400代表了.NET ...
SSH整合是指将Spring、Hibernate和Struts这三大Java开源框架集成在一起,用于构建高效、灵活的企业级Web应用程序。这三个框架分别负责不同的职责:Spring作为应用的基石,提供依赖注入(DI)和面向切面编程(AOP),...
这个是安装说明文件,里面要用的安装文件,除了MYSQL 5。0太大,不能上传,其他的都上传了!!安装文件免费共享了,想快速安装成功的兄弟,请下载这个说明文件,我要收3分哦!我也想去下别人的好东西!...
在协议层,PCIe 5.0继续采用TLP(事务层包)和DLLP(数据链接层包)的设计,但对这些包的处理进行了优化,以减少延迟并提高带宽利用率。同时,它还增强了对流控制、错误处理和多路复用的支持。 总的来说,"NCB-PCI_...
winrar 5.0 + key
ambari-2.7.5 编译过程中四个大包下载很慢,所以需要提前下载,包含:hbase-2.0.2.3.1.4.0-315-bin.tar.gz ,hadoop-3.1.1.3.1.4.0-315.tar.gz , grafana-6.4.2.linux-amd64.tar.gz ,phoenix-5.0.0.3.1.4.0-315....
Centos7 el7.x86_64 官方离线 RPM 安装包,安装指令为 sudo rpm -ivh llvm5.0-devel-5.0.1-7.el8.x86_64.rpm
根据数据库服务器的实际版本,选择5.0+或8.0+的jar包,并正确引入到项目中,可以确保Java应用能够顺利与MySQL进行数据交互。同时,理解JDBC的基本使用方法和最佳实践,有助于提高代码的稳定性和效率。
1. **ThinkPHP5.0框架**:ThinkPHP5.0是基于PHP语言的一个轻量级、快速、强大的开发框架,它遵循MVC(模型-视图-控制器)设计模式,提供了丰富的功能和良好的扩展性。在该项目中,ThinkPHP5.0将作为后台处理逻辑的...
CentOS-5.0-i386-bin-DVD.part06.rar
Understand-5.0.930-Windows-64bit.exe windows Understand-5.0.930-Windows-64bit.exe
在本文中,我们将深入探讨Gradle 5.0 Milestone 1的主要特性和改进,以及它如何影响开发者的工作流程。 1. **性能提升** - **更快的初始化**:Gradle 5.0引入了更快的项目初始化速度,通过缓存项目元数据来减少...
【标题】"达内JAVA TTS5.0 PDF"涵盖了Oracle编程的相关知识,这通常意味着这份资料是关于Java编程与Oracle数据库的结合使用。Oracle编程主要指的是如何利用Java语言进行Oracle数据库的交互,包括数据的增删查改、...
Gradle是一个好用的构建工具 使用它的原因是 1、配置相关依赖代码量少,不会像maven一样xml过多 2、打包编译测试发布都有,而且使用起来方便 3、利用自定义的任务可以完成自己想要的功能
llvm5.0-libs-5.0.1-7.el7.x86-64.rpm
《达内JAVA TTS5.0 PDF——JAVA SE核心1》是针对初学者和有一定基础的Java开发者设计的一份详尽教程,旨在深入探讨Java Standard Edition(Java SE)的核心概念和技术。这份PDF教程出自达内教育,一家知名的IT培训...
JDK1.6.0_07+Tomcat5.0+Myeclipse-8.5.0-搭建开发环境 在软件开发和项目实施中,搭建一个完整的开发环境是一个非常重要的步骤。这个环境包括了JDK、Tomcat和Myeclipse三个主要组件。下面我们将详细介绍如何搭建这个...