《Java基础知识》Java线程的概念
按照规划,从本篇开始我们开启『并发』系列内容的总结,从本篇的线程开始,到线程池,到几种并发集合源码的分析,我们一点点来,希望你也有耐心,因为并发这块知识是你职业生涯始终绕不过的坎,任何一个项目都或多或少的要涉及一些并发的处理。
这一系列文章只能算是对并发这块基本理论知识的一个总结与介绍,想要成为并发高手,必然是需要通过大规模并发访问的线上场景应用,或许以后我有了相关经验了,再给你们做一点分享吧。
基本的进程线程概念
进程和线程算是操作系统内两个很基本、很重要的概念了,进程是操作系统中进行保护和资源分配的基本单位,操作系统分配资源以进程为基本单位。而线程是进程的组成部分,它代表了一条顺序的执行流。
系统中的进程线程模型是这样的:

进程从操作系统获得基本的内存空间,所有的线程共享着进程的内存地址空间。当然,每个线程也会拥有自己私有的内存地址范围,其他线程不能访问。
由于所有的线程共享进程的内存地址空间,所以线程间的通信就容易的多,通过共享进程级全局变量即可实现。
同时,在没有引入多线程概念之前,所谓的『并发』是发生在进程之间的,每一次的进程上下文切换都将导致系统调度算法的运行,以及各种 CPU 上下文的信息保存,非常耗时。而线程级并发没有系统调度这一步骤,进程分配到 CPU 使用时间,并给其内部的各个线程使用。
在分时系统中,进程中的每个线程都拥有一个时间片,时间片结束时保存 CPU 及寄存器中的线程上下文并交出 CPU,完成一次线程间切换。当然,当进程的 CPU 时间使用结束时,所有的线程必然被阻塞。
JAVA 对线程概念的抽象
JAVA API 中用 Thread 这个类抽象化描述线程,线程有几种状态:
- NEW:线程刚被创建
- RUNNABLE:线程处于可执行状态
- BLOCKED、WAITING:线程被阻塞,具体区别后面说
- TERMINATED:线程执行结束,被终止
其中 RUNNABLE 表示的是线程可执行,但不代表线程一定在获取 CPU 执行中,可能由于时间片使用结束而等待系统的重新调度。BLOCKED、WAITING 都是由于线程执行过程中缺少某些条件而暂时阻塞,一旦它们等待的条件满足时,它们将回到 RUNNABLE 状态重新竞争 CPU。
此外,Thread 类中还有一些属性用于描述一个线程对象:
- private long tid:线程的序号
- private volatile char name[]:线程的名称
- private int priority:线程的优先级
- private boolean daemon = false:是否是守护线程
- private Runnable target:该线程需要执行的方法
其中,tid 是一个自增的字段,每创建一个新线程,这个 id 都会自增一。优先级取值范围,从一到十,数值越大,优先级越高,默认值为五。
线程案例:
package demo.knowledgepoints.scheduledtask.run; /***
* 线程类
*/
public class ThreadTest implements Runnable { public static int ticket = 9; @Override
public void run() {
try {
System.out.println("当前线程:"+Thread.currentThread().getName());
while(true){
synchronized (this) {
Thread.sleep(1000L);
if (this.ticket > 0) {
ticket--;
System.out.println(Thread.currentThread().getName() + ":出售一张票!");
System.out.println("剩余票量:" + ticket);
} else {
System.out.println("没有票了!");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package demo.knowledgepoints.scheduledtask.run;
public class ThreadMemo {
public static void main(String[] args) {
ThreadTest threadTest1 =new ThreadTest();
new Thread(threadTest1).start();
new Thread(threadTest1).start();
}
}
运行结果

从案例中我们可以知道:ThreadTest 继承了 Runnable 接口,并且实现了run方法。
在 ThreadMemo 中,我们创建ThreadTest,并且是执行了start() 方法,并没有直接执行run方法。
从运行结果我们可以看出:我们运行了run方法里面的程序。
并且线程1和线程0 交替执行。
下面我们来看看这个线程的执行过程。
Runnable 是一个接口,它抽象化了一个线程的执行流,定义如下:
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
第一步:实现接口Runnable接口。
第二步:创建一个线程,并且将实现Runnable接口的类放进去。
第三步:使用线程的start() 方法,启动线程。这个时候,Jvm会自动去找到run方法,并且执行run方法,同时不影响主进程继续往下执行。
线程案例:
public class Thread1 extends Thread {
public static int ticket = 5;
@Override
public void run() {
try {
System.out.println("当前线程:"+Thread.currentThread().getName());
while(true){
synchronized (this) {
Thread.sleep(2000L);
if (this.ticket > 0) {
ticket--;
System.out.println(Thread.currentThread().getName() + ":出售一张票!"+"剩余票量:" + ticket);
} else {
System.out.println("没有票了!");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ThreadTest1 {
public static void main(String[] args) {
Thread thread = new Thread1();
thread.start();
System.out.println("主线程!");
}
}
运行结果:

这是第二种线程实现方式:继承 Thread 类。
看Thread 类:
class Thread implements Runnable
其实就是实现了Runnable 接口。
列举一下:Thread 方法。
1、sleep
public static native void sleep(long millis)
这是一个本地方法,用于阻塞当前线程指定毫秒时长。
2、start
public synchronized void start()
这个方法可能很多人会疑惑,为什么我通过重写 Runnable 的 run 方法指定了线程的工作,但却是通过 start 方法来启动线程的?
那是因为,启动一个线程不仅仅是给定一个指令开始入口即可,操作系统还需要在进程的共享内存空间中划分一部分作为线程的私有资源,创建程序计数器,栈等资源,最终才会去调用 run 方法。
3、interrupt
public void interrupt()
这个方法用于中断当前线程,当然线程的不同状态应对中断的方式也是不同的,这一点我们后面再说。
4、join
public final synchronized void join(long millis)
这个方法一般在其他线程中进行调用,指明当前线程需要阻塞在当前位置,等待目标线程所有指令全部执行完毕。
参考:https://www.cnblogs.com/yangming1996/p/9503911.html
《Java基础知识》Java线程的概念的更多相关文章
- Java线程:概念与原理
Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...
- java 线程基本概念 可见性 同步
开发高性能并发应用不是一件容易的事情.这类应用的例子包括高性能Web服务器.游戏服务器和搜索引擎爬虫等.这样的应用可能需要同时处理成千上万个请求.对于这样的应用,一般采用多线程或事件驱动的架构.对于J ...
- Java - 线程基本概念
[java并发编程实战]-----线程基本概念 线程状态图 说明:线程共包括以下5种状态.1. 新建状态(New) : 线程对象被创建后,就进入了新建状态.例如,Thread thre ...
- Java线程:概念与使用
Java线程大总结 原文章地址:一篇很老的专栏,但是现在看起来也感觉深受启发,知识点很多,很多线程特点我没有看,尴尬.但是还是整理了一下排版,转载一下. 操作系统中线程和进程的概念 在现代操作系统中, ...
- Java线程:概念与原理(转)
一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在 ...
- Java线程的概念
1. 计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...
- java线程(1)--概念基础
参考:http://lavasoft.blog.51cto.com/62575/99150 http://blog.csdn.net/baby_newstar/article/details/6783 ...
- Java线程:概念及原理
线程是执行的程序中的一个线程. Java虚拟机允许应用程序必须同时运行多个执行线程. 每个线程都有一个优先事项.具有更高优先级的线程优先于线程的优先级较低的执行.每个线程可能会或可能不会也被标记为一个 ...
- JAVA线程基础概念及使用
一.线程和进程的区别 在操作系统中所有运行的任务通常对应一个进程,进程是系统进行资源分配和调度的一个独立单位.线程是进程的组成部分,一个进程最少包含一个线程.并发和并行的区别是,并发指的在同一时刻内, ...
随机推荐
- 将py文件打包为exe文件方法
前提: pip是依赖python的,首先检查下windows机器上有没有安装python,或者有没有添加到环境变量中,如果都没有需要安装或者加入环境变量 安装pip 下载地址: https://pyp ...
- Linux安装redis数据库
这几天在搞redis数据库,花了好大功夫,才成功安装在Linux上,这里将自己的安装步骤分享出来,同时也做个记录,备忘. 新人一枚,不对之处,请多指教! 首先登陆Linux服务器 Linux里,我习惯 ...
- 请求库urllib和urllib3
# coding=utf-8 # urllib """ 使用python的urllib库去模拟浏览器请求网页,常用内容如下: urllib.request 发送HTTP请 ...
- C# VS2019 WebService创建与发布,并部署到Windows Server 2012R
前言 上一次数据库灾备和性能优化后,数据库专家建议,在不扩容的情况下,客户端不能再频繁的扫描数据库了!一句惊醒梦中人,因为我也发现数据库越来越卡了,自从上个项目上线后,就出现了这个情况.后来分析其原因 ...
- P1055 ISBN号码
题目描述 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括99位数字.11位识别码和33位分隔符,其规定格式如x-xxx-xxxxx-x,其中符号-就是分隔符(键盘上的减号),最后一位 ...
- 【Android - IPC】之Serializable和Parcelable序列化
1.序列化的目的 (1)永久的保存对象数据(将对象数据保存到文件或磁盘中): (2)通过序列化操作将对象数据在网络上进行传输(由于网络传输是以字节流的方式对数据进行传输的,因此序列化的目的是将对象数据 ...
- cbv请求分析
CBV源码分析 DRF中中所有视图都是基于CBV形式完成, 所以分析其cbv源码, 了解drf的基本请求流程就比较有必要了. urls.py """下面是一个通用的url ...
- ios webp转换jpg
在项目开发的过程中,遇到了一个问题,就是webp的图片,先解释一下webp是啥,webp是谷歌开发的一种旨在加快图片加载速度的图片格式.图片压缩体积大约只有JPEG的2/3,说白了就是省空间,特别对于 ...
- ThinkPHP 实现数据库事务回滚示例代码
ThinkPHP提供了数据库的事务支持,如果要在应用逻辑中使用事务,可以参考下面的方法: 启动事务: $User->startTrans(); 提交事务: $User->commit( ...
- 链接脚本(Linker Script)用法解析(一) 关键字SECTIONS与MEMORY
1.MEMORY关键字用于描述一个MCU ROM和RAM的内存地址分布(Memory Map),MEMORY中所做的内存描述主要用于SECTIONS中LMA和VMA的定义. 2.SECTIONS关键字 ...