Java并发——线程介绍
前言:
互联网时代已经发展到了现在。从以前只考虑小流量到现在不得不去考虑高并发的问题。扯到了高并发的问题就要扯到线程的问题。你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法。下面让我们先从线程的一些基础开始讲解并发这一个知识体系。
一、线程是什么?
首先我们要明白线程是什么,下面是我从百度百科摘过来的概念:
线程(英语: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并发——线程介绍的更多相关文章
- Java 并发 线程同步
Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...
- Java 并发 线程的优先级
Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于 ...
- Java 并发 线程属性
Java 并发 线程属性 @author ixenos 线程优先级 1.每当线程调度器有机会选择新线程时,首先选择具有较高优先级的线程 2.默认情况下,一个线程继承它的父线程的优先级 当在一个运行的线 ...
- Java 并发 线程的生命周期
Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a) New 新建 b) Runnable 可运行 c) Running 运行 (调用 ...
- Java并发——线程安全、线程同步、线程通信
线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...
- Java并发--线程池的使用
在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...
- Java并发—线程池框架Executor总结(转载)
为什么引入Executor线程池框架 new Thread()的缺点 每次new Thread()耗费性能 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞 ...
- JVM之java并发 ——线程安全与锁优化
概述 人们很难想象现实中的对象在一项工作进行期间,会被不停地中断和切换,对象的属性(数据)可能会在中断期间被修改和变“脏”,而这些事情在计算机世界中则是很正常的事情.有时候,良好的设计原则不得不向现实 ...
- Java并发-线程池篇-附场景分析
作者:汤圆 个人博客:javalover.cc 前言 前面我们在创建线程时,都是直接new Thread(): 这样短期来看是没有问题的,但是一旦业务量增长,线程数过多,就有可能导致内存异常OOM,C ...
随机推荐
- r.js合并实践 --项目中用到require.js做生产时模块开发 r.js build.js配置详解
本文所用源代码已上传,需要的朋友自行下载:点我下载 第一步: 全局安装 npm install -g requirejs 第二步: 1.以下例子主要实现功能, 1)引用jq库获取dom中元素文本, ...
- 【STM32H7教程】第5章 STM32H7下载和调试方法(MDK5)
完整教程下载地址:http://forum.armfly.com/forum.php?mod=viewthread&tid=86980 第5章 STM32H7下载和调试方法(MDK5) 本 ...
- SAP MM Storage Location Missing in MD04 Result?
SAP MM Storage Location Missing in MD04 Result? Today I received a ticket from business team, a user ...
- SQL基础语法
数据库: 结构化查询语言(Structured Query Language)简称SQL: 数据库管理系统(Database Management System)简称DBMS: 数据库管理员(Data ...
- python 线程(一)理论部分
Python线程 进程有很多优点,它提供了多道编程,可以提高计算机CPU的利用率.既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的. 主要体现在一下几个方面: 进程只能在 ...
- June 30th. 2018, Week 26th. Saturday
Curiosity is the wick in the candle of learning. 如果学习是一根蜡烛,那好奇心就是烛芯. From William Arthur Ward. Pleas ...
- Leetcode 136.只出现一次的数字 By Python
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1: 输入: [ ...
- java日志框架log4j详细配置及与slf4j联合使用教程
最后更新于2017年02月09日 一.log4j基本用法 首先,配置log4j的jar,maven工程配置以下依赖,非maven工程从maven仓库下载jar添加到“build path” <d ...
- 深入理解 new 操作符
和其他高级语言一样 JavaScript 也有 new 操作符,我们知道 new 可以用来实例化一个类,从而在内存中分配一个实例对象. 但在 JavaScript 中,万物皆对象,为什么还要通过 ne ...
- Ansible安装及简单使用备注
1.安装epel源: rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm 2.安装: yum ...