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并发的皮毛。后续会介绍更深入的知识点。
上一篇: 程序员爸爸带娃微信群
下一篇: 第一次软件工程作业