从线程说起,从线程结束

这里写图片描述

什么是线程

说起线程,还得从两年前说起……

算了^_^,我直接从WiKi说起吧,WiKi上是这么介绍线程的(不好上中文WiKi的同志可以去Shreagle,那里有办法):

各地线程写法:

  • 英语:Thread
  • 大陆:线程
  • 台湾:執行緒
  • 港澳:線程

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程之中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程可以并发多个线程每条线程并行执行不同的任务。在Unix System VSunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指的是内核线程(kernel thread),而把用户线程称(user thread)为线程。线程是独立调度和分派的基本单位。线程可以操纵系统内核调度的内核线程,如win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符信号处理等等。但同一进程中的不同线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。

一个进程可以有很多线程,每条线程并行执行不同的任务。

在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责IO处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。

嗯,WiKi的介绍基本都解释清楚了什么是线程。

Java中的线程

创建线程

Java中线程的创建有两种方式,继承一个类(Thread)或者是实现一个接口(Runnable),继承的话只能继承一个父类,受到了限制。那实现接口就不一样了,可以实现多个接口,一定程度上不受限制,因此这也是通常用的比较多的创建线程的方式。

  • 继承实现线程
public class ThreadExtend extends Thread {

    @Override
    public void run() {
        //do something
    }

}
  • 接口实现线程
public class ThreadInterface implements Runnable {

    @Override
    public void run() {
        //do something
    }

}

不必要把Runnable接口想的有多复杂,内部进行了多么复杂的操作,其实它只不过是定义了个线程的执行方式,看下面的源码就可以明白,它只定义了一个抽象方法:

package java.lang;
public interface Runnable {    
        public abstract void run();
}

那其实Thread类也是实现了Runnable接口的,来看看Thread源码:

public class Thread implements Runnable {
...
        public void run() {    
                if (target != null) {  
                        target.run();   
                }
        }
...
}

Thread源码中对目标线程对象进行了空检查,如果不为空呢,那这个target对象的run() 方法就会在自己的线程下运行。

Thread方法预览

那在继续了解如何开始结束等一系列的线程操作之前呢,先看看Thread中有哪些常用的方法呢:

  • public static native Thread currentThread();
    `返回当前在执行的线程的对象引用
  • public static native void yield();
    对线程调度器的一个提示,告诉它当前在执行的线程可以退让CPU资源的使用。调度器可以无视这个提示。
  • public static native void sleep(long millis) throws InterruptedException;
    使得当前在执行的线程进入沉睡(暂时的停止)状态,保持指定长度的毫秒数。但是线程不会放弃锁或者是监视器的拥有权。
  • public synchronized void start()
    触发当前线程开始执行,Java Virtual Machine会去调用run()方法来执行指定任务
  • public void run()
    当前线程要执行的特定线程任务
  • @Deprecated public final void stop()
    此方法已弃用。用来强制线程停止执行
  • public void interrupt()
    阻断当前线程的执行
  • @Deprecated public void destroy()
    此方法已经启用,再调用则会抛出NoSuchMethodError异常
  • public final native boolean isAlive();
    测试当前线程是在激活执行,即已经开始且未死亡
  • @Deprecated public final void suspend()
    已弃用,暂停当前线程的执行
  • @Deprecated public final void resume()
    此方法已弃用,恢复一个已经暂停运行的线程到执行状态
  • public final void setPriority(int newPriority)
    设置当前线程的执行优先级
  • public final synchronized void join(long millis)
    如果当前线程的结束需要依赖别的线程执行结果,那么执行这个方法来等待最大毫秒数。0标识永远等待
  • public final void setDaemon(boolean on)
    设置当前线程为后台运行线程或者是用户线程

以上列举出了Thread的大部分方法,有静态方法也有实例方法,同时也附上了方法的简介。

Java线程的6种状态以及生命周期

6种状态

  • new
    线程已经被创建,但是还未启动的状态
  • runnable
    从操作系统的底层来看,JVM的runnable状态可以理解为由两个自状态组成的混合状态。当线程向runnable JVM状态转换时,线程首先进入预备子状态。线程管理程序就会决定线程是否进入开始,运行还是暂停。Thread.yield()是个显式的指令来建议线程管理程序暂停当前在执行的线程,来允许其他线程的执行。
    处于runnable状态的线程,在JVM运行节点看来,它其实是在等待操作性的某些系统资源。
  • timed waiting
  • waiting
    当程序中调用如下几个方法时候,线程便会进入waiting状态 :
    • Object.wait()
    • Thread.join()
    • LockSupport.park()
      线程处于waiting状态其实是在等待其他线程进行一些特定操作。例如一个已经在某对象上调用Object.wati()方法的线程需要等待另一个线程中的一个对象进行Object.notify()或者是Object.notifyAll()的调用。一个执行了Thread.join()方法的线程是需要等待特定线程去结束它。这就意味着线程处于waiting的状态可以通过一些特点条件关联的状态来形成混合状态。
  • blocked
    当线程处于blocked状态,表示正在等待监视器锁以进入同步带模块或者某方法或者是调用Object.wait()方法之后重新进入同步代码块或者是某方法
    同步语句需要两个线程都不互相持有对方需要的监视器锁,需要在执行完代码块或者是方法之后,再释放锁资源。当正在执行的线程持有锁时,其他线程无法获取到这个锁,只有进入blocked状态来等待获取到锁资源。
  • terminated
    当线程执行玩run()方法中的任务之后便进入terminated状态

这些状态是JVM向程序报告的当前的状态。在线程执行线的任意一个节点上,只可能有一种状态。

下面看这张状态转换图,反正我看的头晕,不知道你晕不晕:
这里写图片描述

线程的启动

继承方式

直接上例子:

package org.strongme;

public class ThreadExtend extends Thread {

    private String name;

    public ThreadExtend() {
    }

    public ThreadExtend(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name+" 运行 "+i);
        }
    }

    public static void main(String[] args) {

        ThreadExtend te1 = new ThreadExtend("A");
        ThreadExtend te2 = new ThreadExtend("B");
        te1.start();
        te2.start();

    }

}

运行结果:

A 运行 0
A 运行 1
B 运行 0
A 运行 2
A 运行 3
B 运行 1
A 运行 4
B 运行 2
B 运行 3
B 运行 4

接口方式

直接上例子:

package org.strongme;

public class ThreadInterface implements Runnable {

    private String name;

    public ThreadInterface() {
    }

    public ThreadInterface(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name+" 运行 "+i);
        }
    }

    public static void main(String[] args) {
        ThreadInterface ti1 = new ThreadInterface("A");
        Thread t1 = new Thread(ti1);
        ThreadInterface ti2 = new ThreadInterface("B");
        Thread t2 = new Thread(ti2);
        t1.start();
        t2.start();
    }

}

运行结果:

A 运行 0
B 运行 0
B 运行 1
A 运行 1
A 运行 2
A 运行 3
A 运行 4
B 运行 2
B 运行 3
B 运行 4

线程之Thread.sleep()

使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。

例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了。

总之,sleep()可以使低优先级的线程得到执行的机会,当然也可以让同优先级、高优先级的线程有执行的机会

直接上例子:

package org.strongme;

public class ThreadSleep implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ i);
        }
    }

    public static void main(String[] args) {
        ThreadSleep ts = new ThreadSleep();
        Thread t = new Thread(ts, "测试休眠");
        t.start();      
    }

}

运行结果

测试休眠0//等2秒
测试休眠1//等2秒
测试休眠2

线程之new Thread(...).join()

主线程生成了子线程,而子线程要进行大量耗时的运算,主线程有需要用到子线程的处理结果,只有等到子线程执行完毕才可以继续执行主线程(wait for this thread to die)。

上例子:

package org.strongme;

public class ThreadJoin implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("Thread "+Thread.currentThread().getName()+" running to "+i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

        ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        Thread t = new Thread(tj1,"线程1");
        Thread t2 = new Thread(tj2,"线程2");
        t.start();
        t.join();
        t2.start();

    }

}

[with join()]运行结果:

Thread 线程1 running to 0
Thread 线程1 running to 1
Thread 线程1 running to 2
Thread 线程2 running to 0
Thread 线程2 running to 1
Thread 线程2 running to 2

[without join()]运行结果:

Thread 线程2 running to 0
Thread 线程1 running to 0
Thread 线程2 running to 1
Thread 线程1 running to 1
Thread 线程1 running to 2
Thread 线程2 running to 2

看上面两种不同的运行结果,应该可以看出个究竟了吧。

线程之new Thread(...).yield()

>

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值