前言:

  互联网时代已经发展到了现在。从以前只考虑小流量到现在不得不去考虑高并发的问题。扯到了高并发的问题就要扯到线程的问题。你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法。下面让我们先从线程的一些基础开始讲解并发这一个知识体系。

一、线程是什么?

  首先我们要明白线程是什么,下面是我从百度百科摘过来的概念:

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

  这个概念比较晦涩难懂,我们可以这样理解线程表示的就是一条单独的执行流,一个程序可以包括很多子任务,而这些子任务就是一条线程。这个线程有自己的程序执行计数器,也有自己的栈。程序就是一个进程。平常我们所说的多线程不是很多个程序在一起运行,那叫多进程。多线程则是一个程序里面很多个任务在同时执行。(注意:通常多线程在OS底层是通过时间片分配来实现多线程的,实际上每一个时间片只运行了一条线程)

二、怎么创建线程?

1、继承Thread

public class StudyThread extends Thread {
@Override
public void run() {
System.out.println("学习多线程");
}
}

  你可以理解run方法就是类似于单线程中的main函数,如果这个线程执行,那么就会从run方法内的第一条语句开始执行到结束。但是线程现在就开始执行了吗?不是的,要让线程启动必须要先创建出StudyThread这个类的对象,而后开始调用start方法。注意:如果我们没有调用start方法,而是直接调用run方法,那你就可以认为只是调用了一个普通方法。程序并没有达到多线程,还是单线程。如果调用了start方法,程序就有了两条执行流,新的执行run方法,旧的就继续执行main函数。

  如果是在单CPU的机器上,同一时刻只能有一个线程执行,而多CPU的机器同一时刻就可以有多个线程同时执行。当所有线程执行完后程序才退出。

2、实现Runnable接口

  像我们之前说的设计模式,很多设计模式都涉及到继承,但是Java中只支持单线程。所以我们通常不会用上面的方式,而是去实现Runnable接口。

public class StudyRunnable implements Runnable {
@Override
public void run() {
System.out.println("hello");
}
}

  其余的和继承Thread一样。但是有一点不同的就是

public static void main(String[] args) {
Thread studyThread = new Thread(new StudyRunnable());
studyThread.start();
}

  我们需要创建一个线程类,并且传Runnable对象进去。说到底我们操作的还是Thread类,不过是将继承去掉罢了。

三、线程有哪些方法和属性?

  接下来我们直接看源码来解释

public class Thread implements Runnable {
//线程初始化入口
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
//初始化方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
} //真正的初始化方法
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
} this.name = name; Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */ /* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
} /* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
g.checkAccess(); /*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
} g.addUnstarted(); this.group = g;
this.daemon = parent.isDaemon();
this.priority = parent.getPriority();
if (security == null || isCCLOverridden(parent.getClass()))
this.contextClassLoader = parent.getContextClassLoader();
else
this.contextClassLoader = parent.contextClassLoader;
this.inheritedAccessControlContext =
acc != null ? acc : AccessController.getContext();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize; /* Set thread ID */
tid = nextThreadID();
}
}

  我们注意,在真正的初始化方法中,有以下这些属性会被初始化:

1、Tread类中重要的属性

1.1、name

  线程的名字默认是Thread-后跟一个编号,可以使用默认,通过getName方法得到,也可以通过setName方法自定义名字。

1.2、group

  所属线程组,一个线程必然有所属线程组。Thread与ThradGroup的关系就像元素与集合的关系。

1.3、daemon

  前面我们说过,启动线程就会启动一条单独的执行流,如果整个线程都结束,那么程序就会结束,但是当整个程序只剩下daemon的时候,程序也会退出。daemon线程一般是其他线程的辅助线程,主要作用是负责垃圾回收。

1.4、priority

  线程中的优先级,从1到10,优先级逐渐升高,默认为5。操作方法是用getPriority,setPriority

1.5、stackSize

  预期堆栈大小,不指定默认为0,0代表忽略这个属性。与平台相关,不建议使用该属性。

2、Tread类中一些重要的方法

2.1、getState()

  得到当前线程的线程状态。Thread.State是枚举类型,有NEW(没有调用start的线程状态)、RUNNABLE(调用start后线程在执行run方法且没有阻塞的状态)、BLOCKED(线程被阻塞)、WAITING(线程被阻塞)、TIMED_WAITING(线程被阻塞)、TERMINATED(线程运行结束后的状态) 5种。

2.2、isAlive()

  线程被启动后,run方法结束前,线程都是活的。

2.3、sleep(),yield(),join()

  上面三个方法都可以让控制线程的执行,sleep是让线程睡眠的方法,yield是告诉操作系统调用该方法的线程不急着执行,可以先让其他线程执行,当然操作系统可能接受yield的建议,也有可能不接受。join方法则是将其他线程中断,让调用该方法的线程先执行完再执行其他线程,如果这个执行的过程中被中断,就会抛出Interrupted-Exception

四、总结

  这篇博客只是先简单介绍了一下线程,让我们知道了线程的创建方法,线程初始化的过程,以及线程中一些常用属性和方法。但是这只是Java并发的皮毛。后续会介绍更深入的知识点。

Java并发——线程介绍的更多相关文章

  1. Java 并发 线程同步

    Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...

  2. Java 并发 线程的优先级

    Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于 ...

  3. Java 并发 线程属性

    Java 并发 线程属性 @author ixenos 线程优先级 1.每当线程调度器有机会选择新线程时,首先选择具有较高优先级的线程 2.默认情况下,一个线程继承它的父线程的优先级 当在一个运行的线 ...

  4. Java 并发 线程的生命周期

    Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a)     New 新建 b)     Runnable 可运行 c)     Running 运行 (调用 ...

  5. Java并发——线程安全、线程同步、线程通信

    线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...

  6. Java并发--线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  7. Java并发—线程池框架Executor总结(转载)

    为什么引入Executor线程池框架 new Thread()的缺点 每次new Thread()耗费性能 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞 ...

  8. JVM之java并发 ——线程安全与锁优化

    概述 人们很难想象现实中的对象在一项工作进行期间,会被不停地中断和切换,对象的属性(数据)可能会在中断期间被修改和变“脏”,而这些事情在计算机世界中则是很正常的事情.有时候,良好的设计原则不得不向现实 ...

  9. Java并发-线程池篇-附场景分析

    作者:汤圆 个人博客:javalover.cc 前言 前面我们在创建线程时,都是直接new Thread(): 这样短期来看是没有问题的,但是一旦业务量增长,线程数过多,就有可能导致内存异常OOM,C ...

随机推荐

  1. Supervisor守护DotNet Core控制台程序

    Supervisor 相信对Linux系统很熟的都知道这个软件,基于Python写的一个守护进程软件.具体的介绍和使用我就不再赘述了. 使用asp.net core 部署在Linux常用的方法 我们可 ...

  2. 【STM32H7教程】第12章 STM32H7的HAL库框架设计学习

    完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第12章       STM32H7的HAL库框架设计学 ...

  3. Docker 堆栈

    1.  Stack stack(译:堆叠,堆栈)是一组相互关联的服务,它们共享依赖关系,并且可以一起编排和伸缩. 在上一篇<Docker 服务>中我们知道可以通过创建一个docker-co ...

  4. FreeSql 扩展包实现 Dapper 的使用习惯

    简介 FreeSql.Connection.Extensions 这是 FreeSql 衍生出来的扩展包,实现(Mysql/postgresql/sqlserver/Oracle/SQLite)数据库 ...

  5. Python库的安装

    window下python2.python3安装包的方法 一.在线安装 安装好python.设置好环境变量后,在python安装目录下Script文件夹内会存在pip.exe和easy_install ...

  6. appium+python搭建自动化测试框架_Tools安装(一)

    作者的配置环境和版本: win10 + python3.6 +  Appium v1.4.16 1.下载node   https://nodejs.org/en/download/, 下载node.j ...

  7. 2018-02-24 项目/教程中使用母语命名的"问题"

    早先试图找使用中文命名代码的项目, 但所获寥寥: 索引: 用中文编写代码的实用开源项目 · Issue #6 · program-in-chinese/overview. 更不用说教程了: 索引: 用 ...

  8. Python之路【第二篇】:Python基础

    Python基础 对于Python,一切事物都是对象,对象基于类创建 所以,以下这些值都时对象:"zhurui".22.['北京','上海','深圳'],并且是根据不同的类生成的对 ...

  9. scrapy设置代理的方法

    方法一: 直接在spider文件下设置代理,通过传参的方式设置在Request中 import scrapy class MimvpSpider(scrapy.spiders.Spider): nam ...

  10. Quartz实现分布式可动态配置的定时任务

    关键词: 1. 定时任务 2. 分布式 3. 可动态配置触发时间 一般通过Quartz实现定时任务很简单.如果实现分布式定时任务需要结合分布式框架选择master节点触发也可以实现.但我们有个实际需求 ...