Thread 与 Runnable 线程 初识

本文详细介绍了Java中的线程与多线程概念,包括线程与进程的区别、线程的创建与启动方法、线程的状态转换及控制、线程间的通信机制等。同时还探讨了同步的概念及其实现方式。

Thread 与 Runnable 线程

1.基本概念

  • 程序(program/software)是一段静态的代码,它是应用程序执行的蓝本、脚本。

    类比:开发的售票系统

  • 进程(Process)是指一个正在运行的程序,有自己的地址空间

    正在运行的售票系统

多个进程互不影响各自卖各自的票:机票、火车票、汽车票等各种正在售票的售票系统

  • 线程(Thread)是指进程中的一个执行路径,一个进程中可以并发多个线程,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程(单线程程序)。
    多个网站、窗口同时卖一趟列车的火车票,票数固定,多人一起抢票

2. 进程的特点和状态

  • 进程的特点
    ==动态性、并发性、独立性==
  • 进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程具有以下三种基本状态。
    • 1)就绪状态(Ready)
    • 2)运行状态(Running)
    • 3)阻塞状态(Blocked)

例如:火车站(类比CPU)的列车(类比进程)调度
一个火车站可以同时运行多个列车,但同时只能有一个列车到站、出站

3. 什么是多线程

  • 多线程的定义
    ==进程内部的一个执行单元,它是程序中一个单一的顺序控制流程。如果在一个进程中同时运行了多个线程,用来完成不同的工作或各自完成各自的一样的工作,则称之为多线程。==
  • 线程和进程的区别
    • 进程是系统资源分配的单位,可包括多个线程
    • 线程是独立调度和分派的基本单位,共享进程资源
    • 引入进程是为了多个程序并发执行,提高资源的利用率和系统吞吐量
    • 引入线程是为了减少程序在并发执行时付出的时空开销

3. 线程的创建

  • Java程序启动时,会立刻创建主线程,main就是在这个线程上运行。当不再产生新线程时,程序是单线程的。
  • 两种方法来创建新线程
  • 继承Java.lang.Thread类,并覆盖run()方法

    class MyThread extends Thread {
         public void run( ) {
             /* 覆盖该方法*/
          }
     }
    
  • 实现Java.lang.Runnable接口,并实现run() 方法

    class MyRunnable  implements Runnable{
          public void run( ) {
                /* 实现该方法*/ 
          }
     }
    

4. 线程的启动

  • 新建的线程不会自动开始运行,必须通过start( )方法启动
  • (1)启动继承Thread的线程

    MyThread  myThread1 = new MyThread ();
    myThread1 .start();
    MyThread  myThread2 = new MyThread ();
    myThread2 .start();
    
  • (2)启动实现Runnable接口的线程

        MyRunnable  myRunnable =   new MyRunnable();
        Thread    thread1  =   new Thread(myRunnable);
        Thread    thread2  =   new Thread(myRunnable);
        thread1.start();
        thread2.start();
    

5.Thread类的常用方法


方 法                            | 功 能
---                              |  ---
public Thread()                  | 创建线程对象
public Thread(String name)       | 创建线程对象并指定线程的名称
static Thread currentThread()    | 得到当前线程
final String getName( )          | 返回线程的名称
final void setName(String name)  |将线程的名称设置为由name指定的名称 
void start( )                    | 调用run( )方法启动线程,开始线程的执行
void run( )                      | 存放线程体代码
static void sleep(long millis)   | 线程休眠millis毫秒

6. 两种实现线程的方式的区别

  • 继承Thread类
    • (1)不能再继承其他的类,因为单继承限制
    • (2)多个线程之间共享数据比较复杂(静态static)
    • (3)同步锁也比较复杂(使用线程类的class对象或者静态属性对象或者更复杂的方式)
    • -
  • 实现Runnable接口
    • (1)可以继承其他的类
    • (2)多个线程之间共享数据比较简单
    • (3)同步锁也比较简单(直接使用this对象就行)
    • (4)在线程内获得当前执行的线程信息时比较麻烦,需要使用Thread.currentThread()

7. 线程状态转换

7.1 线程的生命周期
  • 线程的生命周期中的五种状态:就绪、运行、可运行(临时状态),阻塞、死亡(终止)
    • 就绪 - 使用new关键字创建一个线程后,尚未调用其start方法之前
    • 可运行
      • 调用线程对象的start方法之后
      • 这个状态当中,线程对象可能正在运行(运行状态),也可能等待运行(就绪状态)
    • 阻塞
    • 一种“不可运行”的状态,在得到一个特定的事件之后会返回到可运行状态
    • 死亡
    • 线程的run方法运行完毕或者在运行中出现未捕获的异常时
7.2 线程的优先级
  • 线程的优先级用1-10之间的整数表示,数值越大优先级越高,默认的优先级为5
    • 1:Thread.MIN_PRIORITY
    • 5:Thread.NORM_PRIORITY
    • 10:Thread.MAX_PRIORITY

- 线程可以通过setPriority方法更改优先级。优先级不能超出1-10的取值范围,否则抛出IllegalArgumentException

- 高优先级的线程比低优先级的线程有更高的几率得到执行

  • 注意:不要假定高优先级的线程一定先于低优先级的线程执行,不要有逻辑依赖于线程优先级,否则可能产生意外结果
7.3 控制线程的方法
  • 线程的休眠:
    • 当前正在执行的线程休眠指定时间后再加入抢资源的队伍(即恢复就绪状态)
    • Thread.sleep(毫秒)、sleep(毫秒,纳秒)
  • 线程的让步:
    • 当前正在执行的线程让出本次抢到的CPU资源,重新加入抢资源的队伍
    • Thread.yield()
  • 线程的阻塞:
    • 已启动的某线程对象A.join()、join(毫秒)、join(毫秒,纳秒)
    • 例如线程B中调用A.join()方法,那么表示B被阻塞,让A先执行完或者让A执行一段时间后,再恢复B至就绪状态
7.4 线程间通信
  • 依赖Object类有wait和notify方法
方 法功 能
public final void wait()当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待。
public final void wait(long timeout)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量前,导致当前线程等待。
public final void wait(long timeout,int nanos)在其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。
public final void notify()唤醒在此对象监视器上等待的单个线程。
public final void notifyAll()唤醒在此对象监视器上等待的所有线程。
public final void notify()唤醒在此对象监视器上等待的单个线程。

8.同步

8.1 同步的实现方式
  • 同步方法:直接在方法前面加synchronized
  • 同步代码块:
    • synchronized(对象锁){需要同步的操作代码}
    • 对象锁(类比:令牌),只有持有对象锁的线程才能进入同步块中执行代码,否则只有等待
8.2 同步锁(lock) 也叫互斥锁(mutex)、监视锁(Monitor)

同步锁
- 在Java虚拟机中,每个对象和类(class对象)都关联了一把锁,或者说每个对象本身就是一把锁。

  • 同步方法默认使用的就是this对象作为同步锁
  • 如果每个线程不是共用一个线程类的对象的,那么使用this就不是同一把锁,所以有必要为这些线程重新指定一把锁
  • 使用同步块所在类的class对象(使用最多)
  • 使用同步块所在类的一个静态属性对象

- 提示:当然关于锁还有更复杂的情况,大家可以查看jdk1.5引入的java.util.concurrent.locks和atomic包的相关知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值