【系列】重新认识java——线程(Thread)

多线程编程是开发者必须要掌握的基本技能,线程(Thread)是基础和核心。只有深刻地理解Java线程,才能写出合理、高效的多线程代码。本文将研究Java中的线程,同时会捎带部分操作系统相关内容。主要的内容如下:

  1. 进程与线程
  2. Java线程(线程创建、Thread中的主要方法、线程通信)

进程与线程

进程与线程,是操作系统中的重要概念,稍微有点计算机基础的开发者都会听说过、接触过。

进程(Process):计算机中的程序关于某数据集合上的一次运行活动,是操作系统结构的基础(来自百度百科)。狭义上来说,进程是正在运行的程序实例。进程和程序间的关系很微妙,用一个比喻(来自《现代操作系统》)来说明。有一位拥有一手好厨艺计算机科学家正在为女儿烘制蛋糕,他有制作蛋糕的食谱,还有一些原料(面粉、鸡蛋等)。在这个例子中,食谱就是程序(用适当形式描述的算法),科学家就是CPU,原料就是各种输入数据。那么,进程就是食谱、原料以及烘制蛋糕的系列动作的总和。

线程(Thread):有时也被称为轻量级进程,是程序调度和执行的最小单元。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个进程可以包含多个线程,而一个线程只能属于唯一的进程。

已经有了进程,为什么还会需要线程呢?主要原因如下:

  1. 许多应用程序中,同时发生着多个活动。将这些应用程序分解成多个准并行的线程,程序设计的模型会变成更加简单。
  2. 由于线程比进程进行更加轻量,创建和取消更加容易。
  3. 如果程序是IO密集型,那么多线程执行能够加快程序的执行速度。(如果是CPU密集型,则没有这个优势)
  4. 在多CPU系统中,多线程是可以真正并行执行的。

Java线程

线程状态

java-thread-state

  1. 新建状态(New):线程对象已经创建,还没有在其上调用start()方法。
  2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
  3. 运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
  4. 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    • 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
    • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    • 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

创建和启动线程

Java中有两种方法定义线程:

1、继承java.lang.Thread类。

/**
 * 进程Thread类定义线程。
 * @author xialei
 * @version 1.0 2016年8月1日下午9:22:37
 */
public class MyThread extends Thread {
   

    @Override
    public void run() {
        System.out.println("Hello");
    }
}

上面的代码继承了java.lang.Thread类,然后重写了run()方法。该方法的方法体内是线程需要完成的任务,称为线程执行体。下面的代码启动这个线程:

MyThread myThread = new MyThread();
myThread.start();

通过调用Thread类中的start()方法启动线程,这方法最终会调用start0()native方法启动线程。调用start()方法,使得该线程进入到就绪状态,此时此线程并不一定会马上得以执行,这取决于CPU调度时机。

2、实现java.lang.Runnable接口。

/**
 * 实现Runnable接口定义线程。
 * @author xialei
 * @version 1.0 2016年8月1日下午9:28:28
 */
public class MyRunnable implements Runnable {
   

    @Override
    public void run() {
        System.out.println("Hello");
    }

}

调用下面的代码可以启动线程。

Thread thread = new Thread(new MyRunnable());
thread.start();

MyRunnable类本身并不能启动线程,而是需要实例化一个Thread类来启动线程。可以看到,不管是哪种方法,都是调用Threadstart()方法来启动的。Thread类和Runnable接口到底是什么关系呢?实际上,Thread类本身就实现了Runnable接口,Thread中的run()就是实现了Runnable中的run()方法,其代码如下:

public void run() {
    if (target != null) {
        target.run();
    }
}

通过Thread(Runnable)构造方法可传入Runnable对象,然后直接调用其run()方法。

线程类型

Java中的线程有用户(User)线程和守护(Daemon)线程两类。我们默认创建的线程是用户(User)线程,守护线程–也称“服务线程”,在没有用户线程可服务时会自动离开。只要当前JVM实例中尚存在任何存货的用户线程,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

下面来分别演示一下这两类线程。

public class UserThreadTest {
   

    public static void main(String[] args) {
        Thread t &
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值