JAVA线程

来源:互联网 发布:eagle软件官网 编辑:程序博客网 时间:2024/05/17 02:08

JAVA线程

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

概念及类别:

线程总体分两类:用户线程和守护线程。

守护线程概念:后台线程主要是为其它线程(相对可以称之为前台线程)提供服务,或”守护线程”。如JVM中的垃圾回收线程。
生命周期:当所有的前台线程都进入死亡状态时,后台线程会自动死亡

生命周期及五种基本状态:

关于Java中线程的生命周期,首先看一下下面这张较为经典的图:

新建状态(NEW): 当线程对象创建后即进入了新建状态。
就绪状态(Runnable): 当调用线程对象的Start()方法,线程即进入就绪状态。处于就绪状态的线程只是说明此线程已经做好了准备,随机等待CPU调度执行,并不是说执行了Start()此线程立即就会执行。
运行状态(Running): 当CPU开始调度处于就绪状态的线程时,此线程才真正执行,即进入运行状态。
阻塞状态(Blocked): 处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1、等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态。
2、同步阻塞:线程在获取Synchronized同步锁失败(因为锁被其它线程锁占用),它会进入同步阻塞状态。
3、其它阻塞:通过调用线程的Sleep()或join()或发出了I/O请求时,线程会进入阻塞状态。当Sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程创建方式

1、继承Tread类,重写该类的run()方法。
2、实现Runnable接口,并重写该接口的run()方法。
3、使用Callable和Future接口创建线程,具体是创建Callable接口的实现类并实现call()方法。并使用FutureTask类来包装Callable实现类的对象。

线程同步

  1. 同步方法

    即有sychronized关键字修饰的方法,由于java的每个对象都有一个内置锁,当用此关键字修饰方法时内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

  2. 同步代码块

    即有sychronized关键字修饰的语句块,被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。

  3. 使用特殊域变量(volatile)实现线程同步

    volatile关键字为域变量的访问提供了一种免锁机制,使用volatile修饰域相当于告诉虚拟机该域可能会被其它线程更新,因此每次使用该域就要重新计算而不是使用寄存器中的值。volatile不会提供任何原子操作,它也不会用来修饰final类型的变量

  4. 使用重入锁实现线程同步

    ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchonized方法和块具有相同的基本行为和语义,并且扩展了其能力。
    ReentrantLock():创建一个ReentrantLock实例
    Lock():获得锁
    unLock():释放锁

  5. 使用局部变量实现线程同步

    如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间互相独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其它线程产生影响。
    ThreadLocal():创建一个线程本地变量
    get():返回此线程局部变量的当前线程副本中的值
    initialValue():返回此线程局部变量的当前线程的”初始值”
    set(T value):将此线程局部变量的当前线程副本中的值设置为value

  6. 使用阻塞队列实现线程同步

    前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。使用java.util.concurrent包将有助于简化开发。
    LinkedBlockingQueue是一个基于已连接节点的,范围任意的blocking queue.队列是先进先出的顺序(FIFO)
    put(E e):在队尾添加一个元素,如果队列满则阻塞
    size():返回队列中的元素个数
    take():移除并返回队头元素,如果队列空则阻塞

  7. 使用原子变量实现线程同步

    需要使用线程同步的根本原因在于对普通变量的操作不是原子的。
    原子操作就是指将读取变、修改变、保存变量值看成一个整体来操作,即这几种行为要么同时完成,要么都不完成。
    Atomiclnteger表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),但不能用于替换Integer;可扩展Number,允许那些处理机域数字类的工具和实用工具进行统一访问。
    addAddGet(int dalta):以原子方式将给定值与当前值相加
    get():获取当前值

0 0