关于Java多线程的一些知识点总结

以下为自己学习多线程的时候总结的一些知识点

同时推荐一本很好的关于多线程高并发的书籍:《Java高并发编程详解》

  1. 线程的生命周期:创建,就绪,运行,阻塞,死亡
    新建状态:当使用new关键字和Thread类或者子类建立了一个线程对象,该线程对象就处于新建状态。它保持这个状态直到程序start()这个线程。
    就绪状态:当线程对象调用了start()方法之后,该线程就进入了就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里的线程调度器的调度。
    运行状态:如果就绪状态的线程获取CPU资源,就可以执行run(),此时线程便处于运行状态。
    阻塞状态:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占有的资源之后,该线程就从运行状态进入阻塞状态。
    等待阻塞:运行状态中的线程执行wait()方法,使线程进入等待阻塞状态。
    同步阻塞:线程在获取sychronized同步锁失败。
    其他阻塞:通过调用线程的sleep()或者join()发出了I/O请求,线程就进入了阻塞状态。
    死亡状态:~~~~~~~

  2. 创建一个线程的方法:
    继承Thread类
    实现Runnable接口
    实现Callable接口与Future结合

  3. 推荐创建单线程的时候使用继承Thread方式创建,创建多线程的时候使用Runnable、Callable接口来创建。
    ·继承Thread类创建的线程,可以直接使用Thread类中的方法,比如使用sleep方法,而不必在前面加上一个Thread。
    使用Thread类的局限性:资源不能共享,无法放入线程池中等。
    ·使用Runnable、Callable接口的方式创建线程,可以实现资源共享,增强代码的复用性,并且可以避免单继承的局限性,可以和线程池完美结合。

  4. yield():表示暂停当前正在执行的线程,并执行其他线程。只是使当前线程回到可执行状态,有可能进入可执行状态后马上又被执行
    sleep():使当前线程进入停滞状态,所以执行sleep()的线程在指定的时间内肯定不会被执行。

  5. join(): 等待某个线程终止,才执行后面的代码。

  6. 线程的优先级:setPriority()设置线程的优先级
    Thread,MIN_PRIORITY(最低优先级、取值为1)
    Thread,MAX_PRIORITY(最高优先级、取值为10)
    Thread,NORM_PRIORITY(默认优先级、取值为5)

  7. 线程中常用的方法:
    sleep():在指定的毫秒数内让当前正在执行的线程休眠(暂停执行);不会释放对象锁。
    join():只等待t线程终止。
    yield():暂停当前正在执行的线程对象,并执行其他线程。
    setPriority():设置一个线程的优先级。
    interrupt():调用当前线程的interrupt方法,可以打断阻塞。
    wait():强迫一个线程等待。它是一个Object的方法。wait方法会释放对象锁,让其他线程可以访问。
    isAlive():判断一个线程是否存活。
    activeCount():程序中活跃的线程数。
    currentThread():得到当前线程。
    setDaemon():设置一个线程为守护线程(用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束)。
    setName():为线程设置一个名称。
    notify():通知一个线程继续运行,也是一个Object方法,通常和wait方法一起使用。

  8. sleep()和wait()区别:
    ·使用sleep方法可以让当前线程休眠,时间一到当前线程继续往下执行,在任何地方都能使用,但需要捕获InterruptedException异常。
    ·使用wait方法则必须放在synchronized块里面,同样需要捕获InterruptedException异常,并且需要获取对象的锁。
    ·wait方法还需要额外的方法notify/notifyAll进行唤醒,它们同样需要放在synchronized块里面,且需要获取对象的锁。
    使用场景:sleep一般对于当前线程休眠,或者轮循暂停操作,wait则多用于多线程之间的通信。
    ·sleep是Thread类的静态本地方法,wait则是Object类的本地方法。
    ·sleep会让出CPU执行时间且强制上下文切换,而wait则不一定,wait后可能还有机会重新竞争到锁继续执行。

  9. 并行:多个CPU实例或者多台机器同时执行一段处理逻辑,是真正的同时。
    并发:通过cpu调度算法。让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。

  10. 继承Thread类的方法实现线程安全 static方法

  11. 两个线程同时访问一个对象的相同的synchronized方法
    同一实例拥有同一把锁,其他线程必然等待,顺序执行

  12. 两个线程同时访问两个对象的相同的synchronized方法
    不同的实例拥有的锁是不同的,所以不影响,并行执行

  13. 两个线程同时访问两个对象的相同的static的synchronized方法
    静态同步方法,是类锁,所有实例是同一把锁,其他线程必然等待,顺序执行

  14. 两个线程同时访问同一对象的synchronized方法与非synchronized方法
    非synchronized方法不受影响,并行执行

  15. 两个线程访问同一对象的不同的synchronized方法
    同一实例拥有同一把锁,所以顺序执行(说明:锁的是this对象==同一把锁)

  16. 两个线程同时访问同一对象的static的synchronized方法与非static的synchronized方法
    static同步方法是类锁,非static是对象锁,原理上是不同的锁,所以不受影响,并行执行

  17. 方法抛出异常后,会释放锁吗
    会自动释放锁,这里区别Lock,Lock需要显示的释放锁

  18. 重写Thread类的run方法和实现Runnable接口的run方法还有一个很重要的不同,Thread类的run方法不能共享,
    而使用Runnable接口实现实现这一点。使用同一个Runnable的实例构造不同的Thread实例。

  19. 一个线程的创建肯定是由另一个线程完成的。 被创建的线程的父线程是创建他的线程。

  20. main线程所在的ThreadGroup称为main;构造一个线程的时候如果没有显式地指定ThreadGroup,name它将会和父线程同属于一个ThreadGroup

  21. 使用TimeUnit代替Thread.sleep
    枚举类TimeUnit对sleep方法提供了封装,可以省去单位换算步骤
    线程休眠3小时24分钟14秒33毫秒可以表示为:
    TimeUnit.HOURS.sleep(3)
    TimeUnit.MINUTES.sleep(24)
    TimeUnit.SECONDS.sleep(14)
    TimeUnit.MILLISECONDS.sleep(33)

  22. synchronized注意点:
    ·与monitor关联的对象不能为空
    ·synchronized作用域太大,由于synchronized关键字存在排他新,也就是说所有的线程必须串行的经过synchronized保护的共享区域
    如果synchronized作用域越大,则代表着其效率越低,甚至还会丧失并发的优势。
    ·this Monitor 对于同一实例有影响
    ·class Monitor与static synchronized 作用一样 都是类锁,对整个类有影响。

  23. 同步代码的monitor必须与执行wait notify方法的对象一致,简单地说就是用哪个对象的monitor进行同步,就只能用哪个对象进行wait和notify操作。

  24. Java通过Executors提供四种线程池,分别为:
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

  25. RejectedExcecutionHandler线城市四种拒绝任务策略:
    DiscardPolicy 直接丢弃
    DiscardOldestPolicy 丢弃队列中最老的任务
    AbortPolicy 抛异常
    CallerRunsPolicy 将任务分配给调用线程来执行

  26. 关闭线程池的两个方法:
    shutdown:线程池拒绝接受新提交的任务,同时立马关闭线程池,线程池里的任务不再执行。
    shutdownNow: 线程池拒绝接收新提交的任务,同时立马关闭线程池,线程池里的任务不再执行。

  27. 饿汉式单例模式在多线程下可以保证只有一个实例,但是不能实现懒加载;
    懒汉式单例模式在多线程下不能保证只有一个实例,但是可以采用在getInstance方法前加上static synchronized同步约束。 性能比较低下。

原创文章 23 获赞 11 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_40777510/article/details/102823433
今日推荐