在说线程之前先说下进程,进程和线程都是一个时间段的描述,是CPU工作时间段的描述。
进程,是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竟争计算机系统资源的基本单位。每一个进程都有一个自己的地址空间,即进程空间或(虚空间)。
线程,在网络或多用户环境下,一个服务器通常需要接收大量且不确定数量用户的并发请求,为每一个请求都创建一个进程显然是行不通的,——无论是从系统资源开销方面或是响应用户请求的效率方面来看。因此,操作系统中线程的概念便被引进了。线程,是进程的一部分,一个没有线程的进程可以被看作是单线程的。线程有时又被称为轻权进程或轻量级进程,也是 CPU 调度的一个基本单位。
线程的创建有三种方式:继承Thread,实现Runnable接口,利用Callable跟Future
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。 (2)创建Thread子类的实例,即创建了线程对象。 (3)调用线程对象的start()方法来启动该线程。
- public class FirstMethod extends Thread {
- @Override
- public void run() {
- super.run();
- }
- }
- FirstMethod firstMethod = new FirstMethod();
- firstMethod.start();
- public class SecondMethod implements Runnable{
- @Override
- public void run() {
- }
- }
- SecondMethod secondMethod=new SecondMethod();
- new Thread(secondMethod).start();
1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。 (2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。 (3)使用FutureTask对象作为Thread对象的target创建并启动新线程。 (4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
- public
- class
- ThirdMethod
- implements
- Callable
- <
- String
- >
- {
- @Override
- public
- String
- call
- ()
- throws
- Exception
- {
- return Thread.currentThread().getName();
- }
- }
- ThirdMethod thirdMethod=new ThirdMethod();
- FutureTask<String> futureTask=new FutureTask<String>(thirdMethod);
- try {
- String threadName = futureTask.get();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值,后者线程执行体run()方法无返回值,因此可以把这两种方式归为一种这种方式与继承Thread类的方法之间的差别如下:
1、接口创建线程可以实现资源共享,比如多个线程可以共享一个Runnable资源 2、但是编程稍微复杂,如果需要访问当前线程,必须调用Thread.currentThread()方法。 3、接口创建线可以避免由于Java的单继承特性而带来的局限。
现在通过一个程序员改Bug的例子来描述一下,一共有15个bug,现在安排3个程序员去Debug:
通过Thread来实现
- public class BugThread extends Thread {
- private volatile int bugNumber = 5;
- @Override public void run() {
- for (int i = 0; i < bugNumber; i++) {
- System.out.println("bugNumber--->" + bugNumber--);
- }
- }
- }
- public class Main {
- public static void main(String[] args) {
- new BugThread().start();
- new BugThread().start();
- new BugThread().start();
- }
- }
运行结果:
- Thread-0-----5
- Thread-1-----5
- Thread-2-----5
- Thread-0-----4
- Thread-2-----4
- Thread-1-----4
- Thread-2-----3
- Thread-0-----3
- Thread-2-----2
- Thread-1-----3
- Thread-2-----1
- Thread-0-----2
- Thread-0-----1
- Thread-1-----2
- Thread-1-----1
通过Runnable来实现
- public class BugRunnable implements Runnable {
- private volatile int bugNumber = 15;
- @Override
- public void run() {
- while (bugNumber > 0)
- System.out.println(Thread.currentThread().getName() + "-----" + bugNumber--);
- }
- }
- public static void main(String[] args) {
- BugRunnable bugRunnable = new BugRunnable();
- new Thread(bugRunnable).start();
- new Thread(bugRunnable).start();
- new Thread(bugRunnable).start();
- }
运行结果
- Thread-0-----15
- Thread-0-----14
- Thread-0-----13
- Thread-0-----12
- Thread-1-----11
- Thread-0-----10
- Thread-1-----9
- Thread-0-----8
- Thread-1-----7
- Thread-0-----6
- Thread-1-----5
- Thread-0-----4
- Thread-1-----3
- Thread-0-----2
- Thread-1-----1
- private volatile char name[]; //线程名称的字节数组
- private int priority; //线程优先级
- private boolean single_step; //线程是否单步
- private boolean daemon = false; //是否是守护线程
- private boolean stillborn = false; //JVM state
- private Runnable target; //从构造方法传过来的Runnable
- private ThreadGroup group; //线程组
- private ClassLoader contextClassLoader; //类加载器
- private static int threadInitNumber; //线程编号
- private volatile int threadStatus = 0; //初始状态
- public final static int MIN_PRIORITY = 1; //最低优先级
- public final static int NORM_PRIORITY = 5; //默认优先级
- public final static int MAX_PRIORITY = 10; //最高优先级
- public enum State {
- //Thread state for a thread which has not yet started.
- NEW,
- //Thread state for a runnable thread.
- RUNNABLE,
- //Thread state for a thread blocked waiting for a monitor lock.
- BLOCKED,
- // Thread state for a waiting thread.
- WAITING,
- //Thread state for a waiting thread with a specified waiting time.
- TIMED_WAITING,
- //Thread state for a terminated thread
- TERMINATED;
- }
线程的状态有NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED,可以整理成如下表格
线程状态 | 解释 |
---|---|
New | 还未调用 start() 方法 |
RUNNABLE | 调用了 start() ,此时线程已经准备好被执行,处于就绪队列 |
BLOCKED | 线程阻塞于锁或者调用了 sleep |
WAITING | 线程由于某种原因等待其他线程 |
TIME_WAITING | 与 WAITING 的区别是可以在特定时间后自动返回 |
TERMINATED | 执行完毕或者被其他线程杀死 |
Thread有很多构造方法,但是通过观察最终调用了如下方法:
- /**
- * Initializes a Thread.
- *
- * @param g //线程组
- * @param target //构造方法传过来的Runnable
- * @param name //线程名称
- * @param stackSize //给线程分配的栈的深度
- * @param acc //上下文加载器
- */
- private void init(ThreadGroup g, Runnable target, String name,
- long stackSize, AccessControlContext acc) {
- if (name == null) {
- throw new NullPointerException("name cannot be null");
- }
- this.name = name.toCharArray();
- Thread parent = currentThread();
- SecurityManager security = System.getSecurityManager();
- //判断线程组参数是否为空
- if (g == null) {
- if (security != null) {
- g = security.getThreadGroup();
- }
- if (g == null) {
- g = parent.getThreadGroup();
- }
- }
- g.checkAccess();
- 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;//初始化target
- setPriority(priority);//设置优先级
- if (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();//设置线程ID
- }
- public
- synchronized
- void
- start
- ()
- {
- if (threadStatus != 0)//判断线程是否准备好
- group.add(this);//将启动的线程线程组
- boolean started = false;
- try {
- start0();//本地方法,JVM调用target的run方法
- started = true;//更改启动标志
- } finally {
- try {
- if (!started)
- group.threadStartFailed(this);//通知线程组启动失败
- }
- } catch (Throwable ignore) {
- /* do nothing. If start0 threw a Throwable then
- it will be passed up the call stack */
- }
- }
- }
- @Override
- public
- void
- run
- ()
- {
- if (target != null) {
- target.run();
- }
- }
synchronized 关键字说明start方法是同步的,并且是启动这个线程进行执行,JVM将会调用这个线程的run方法,这样产生的结果是,两个线程执行着,其中一个是调用start()方法的线程执行,另一个线程是执行run方法的线程。
- public static void sleep(long millis, int nanos)
- throws InterruptedException {
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (nanos < 0 || nanos > 999999) {
- throw new IllegalArgumentException(
- "nanosecond timeout value out of range");
- }
- if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
- millis++;
- }
- sleep(millis);//调用本地方法
- }
线程休眠一段时间,让其他线程有机会继续执行,需要捕捉异常。
- public
- static
- native
- void
- yield
- ()
- ;
- public final synchronized void join(long millis) throws InterruptedException {
- long base = System.currentTimeMillis();
- long now = 0;
- if (millis < 0) {
- throw new IllegalArgumentException("timeout value is negative");
- }
- if (millis == 0) {
- while (isAlive()) {
- wait(0);
- }
- } else {
- while (isAlive()) {
- long delay = millis - now;
- if (delay <= 0) {
- break;
- }
- wait(delay);
- now = System.currentTimeMillis() - base;
- }
- }
- }
join方法是等待该线程执行,直到超时或者终止,可以作为线程通信的一种方式,A线程调用B线程的join(阻塞),等待B完成后再往下执行。
yield跟join
- public
- void
- interrupt
- ()
- {
- if (this != Thread.currentThread())
- checkAccess();//检查权限
- synchronized (blockerLock) {
- Interruptible b = blocker;
- if (b != null) {
- interrupt0();
- b.interrupt(this);
- return;
- }
- }
- interrupt0();
- }
interrupt()方法是中断当前的线程, 此外还有isInterrupt,以及interrupted方法
前面说过,Java中的线程在底层是通过共享内存进行通信的,在应用层则是通过调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。 Object是所有类的超类,主要通过:notify()、notifyAll()、wait()、wait(long)和wait(long,int)这几个方法来进行线程间通信。
1、wait()
- public final void wait() throws InterruptedException,IllegalMonitorStateException
2、notify()
- public final native void notify() throws IllegalMonitorStateException
3、notifyAll()
- public final native void notifyAll() throws IllegalMonitorStateException
wait()和sleep()的区别
通过对线程源码的简单分析,可以看出线程也是有自己的生命周期的,但是由于源码中有很多native方法,导致了很难追踪源码,所以只能大致理解一下线程的各种状态以及通信过程,下面可以通过一副流程图来总结一下:
Java编程思想 wangchangchung.github.io www.jianshu.com/p/5b9fdae43…
来源: https://juejin.im/post/5a2948ce6fb9a0450e7604d1