码迷,mamicode.com
首页 > 编程语言 > 详细

Java多线程基础

时间:2019-10-06 18:33:29      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:adl   实例变量   csdn   绑定   计数器   同步方法   class   box   eth   

线程内存模型

参考:

多线程-内存模型
java线程详解

概述:每个线程都有自己的工作内存,在JVM层面,包含:

  • 程序计数器
  • 线程栈

线程分类

常规划分为两类:

  • 用户线程:除守护线程都是用户线程
  • 守护线程:为用户线程提供一种通用的服务,典型如GC线程,当进程中不存在非守护线程,则守护线程会自动销毁
  • 用户线程转变为守护线程:用户线程在start之前可以通过setDaemo(true)来转变为守护线程。如果在start之后调用setDaemo(true),将会throw IllegalThreadStateException, 参考用户线程和守护线程

线程状态

参考:

线程的五种状态

线程可以分为5种状态:

  • 初始(new): 刚创建的线程
  • 就绪(Runnable): 线程被其他线程(如main线程)调用了该线程对象的start()方法,即会进入就绪线程池,等待cpu以随机的时间调用线程的run()方法,运行线程
  • 运行(Running): 线程获得了cpu 时间片(timeslice), 正在执行程序代码。
  • 阻塞(Blocked): 阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:

(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

  • 死亡(Dead) :线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

线程不安全

当多个线程对同一个对象的实例变量(全局变量),进行读写时,发生变量值不一致,在多个线程间值不同步的情况,进而影响程序执行流程


start()

  • 线程通过start()方法通知“线程规划器”此线程已经准备就绪,等待调用线程对象的run()方法运行线程
  • 如果有多个线程start,cpu对线程的调用是随机的,即执行start()方法的顺序不代表线程的启动顺序(具有异步执行的效果)
  • 如果调用thread.run()就不是异步执行,而是同步,那么此线程对象并不交给“线程规划器”来进行处理,而是由main主线程来调用run()方法,也就是必须等待run()方法中的代码执行完毕后才执行后面的代码
  • 线程执行run方法,即创建一个栈帧在自己的线程栈中

共享变量

  • 局部变量不是共享变量,当多个线程指向同一个线程对象时(该线程对象位于堆中),线程对象中的局部变量会在每个线程栈中单独读写,参考java中的变量类型
  • 共享变量,该变量位于堆区,多个线程都可以进行读写
  • 为了保证共享变量在多个线程间的可见性,可以通过synchronized和volatile关键字,锁机制等

synchronized关键字

  • synchronized关键字可以加在任意方法和对象前,即对它们上锁,而加锁的这段代码称为同步代码,解决多个线程之间访问资源的同步性(保证原子性和可见性)
  • 当一个运行状态的线程想要执行同步代码时,需要先拿到这上面的锁,如果拿不到(被别的线程占用),会和处于锁标志等待池(lock pool)的线程都会一直尝试争夺这把锁
  • synchronized取得的锁都是对象锁,如下:

    1: 修饰实例方法,锁为当前实例对象
    2: 修饰静态方法,锁为当前类的class对象
    3: 修饰代码块,锁可以设置this(当前实例对象),或是this.class(当前类的class对象),或是其他对象

  • synchronized锁重入,当一个线程得到一个对象锁后,再次请求此对象锁(同一把锁)时可以再次得到,如:

    1: 在一个synchronized方法/块的内部调用本地的其他synchronized方法/块时,是永远可以得到锁的
    2: 父子类继承关系中,子类可以通过可重入锁调用父类的同步方法

  • 深入理解Java并发之synchronized实现原理


volatile关键字

  • 当修饰共享变量时,可以保证变量在多线程下的可见性,不保证原子性
  • 当CPU发现是volatile修饰的共享变量时,会通知其他线程缓存的该变量无效,当其他线程读写该变量时,发现无效后会重新从主存中加载数据
  • 全面理解Java内存模型(JMM)及volatile关键字

线程中断

  • 停止线程即在一个线程未完成任务前放弃当前的操作
  • java中停止正在运行的线程:

    1:使用退出标志,之后当线程运行完run方法后线程终止
    2:使用stop()方法强行终止,不推荐,stop(),suspend(),resume()方法都是过期作废的
    3: 使用 return 停止异常,即run()方法中符合条件后return,也会终止线程
    4:使用异常法(推荐),如:

    (1)先调用线程的interrupt()方法,在运行run()方法中出现sleep(),会抛出InterruptedException异常,终止线程
    (2)先在run()方法中出现sleep()方法,之后被调用interrupt()方法,也会抛出InterruptedException异常
    (3)未处理的RuntimeException,发生异常后线程终止


wait(),notify(),notifyAll()

  • wait()方法即让当前线程释放对象琐,进入线程等待队列
  • notify()即从线程等待队列中移出任意一个线程放入锁池中,争抢对象锁
  • notifyAll()即将等待队列的所有线程移入锁池中

join()

  • join()会让所属线程X运行run方法,而让当前线程Y进入无限期阻塞,等待X销毁后,再继续执行Y后面的代码
  • 在Y的run()方法中执行X.join()后,如果此时被Z线程调用Y.interrupt(),则Y线程会抛出InterruptedException异常,X线程正常运行
  • join(long)内部采用的是wait(long),会让当前线程释放锁,而sleep(long)不会让当前线程释放锁,即调用sleep(long)后,其他线程不能执行当前线程的同步方法

ThreadLocal

  • ThreadLocal对象有get()和set()方法,会将放入其中的变量与调用set()方法的线程绑定,使每个线程都可以向其中存放自己的私有变量
  • InheritableThreadLocal类,可以让子线程获取到父线程存放在InheritableThreadLocal对象中的值

Java多线程基础

标签:adl   实例变量   csdn   绑定   计数器   同步方法   class   box   eth   

原文地址:https://www.cnblogs.com/wuba/p/11627770.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!