Java 多线程设计模式之基础概念

栏目: Java · 发布时间: 6年前

内容简介:用于表示多个操作“依次处理”。比如把十个操作交给一个人来处理时,这个人要一个一个地按顺序来处理用于标识多个操作“同时处理”。比如十个操作分给两个人处理时,这两个人就会并行来处理。相对于顺序和并行来说比较抽象,用于表示“将一个操作分割成多个部分并且允许无序处理”。比如将十个操作分成相对独立的两类,这样便能够开始并发处理了。如果一个人来处理,这个人就是顺序处理分开的并发操作,而如果是两个人,这两个人就可以并行处理同一个操作。

用于表示多个操作“依次处理”。比如把十个操作交给一个人来处理时,这个人要一个一个地按顺序来处理

并行

用于标识多个操作“同时处理”。比如十个操作分给两个人处理时,这两个人就会并行来处理。

并发

相对于顺序和并行来说比较抽象,用于表示“将一个操作分割成多个部分并且允许无序处理”。比如将十个操作分成相对独立的两类,这样便能够开始并发处理了。如果一个人来处理,这个人就是顺序处理分开的并发操作,而如果是两个人,这两个人就可以并行处理同一个操作。

总结

多线程程序都是并发处理的。如果 CPU 只有一个,那么并发处理就是顺序执行的,而如果有多个 CPU,那么并发处理就可能会并行运行。

并发处理的顺序执行与并发处理的并行执行示意图如下所示

Java 多线程 <a href='https://www.codercto.com/topics/17995.html'>设计模式</a> 之基础概念

线程启动与中止

启动方式

Thread
Runnable

以上两种方式都需要使用 start 方法用于启动新的线程,在此需要注意的事情是,启动新线程调用的是 start 方法而不是 run 方法

终止

直到所有的线程都终止后,程序才会终止。也就是说,当这两个线程都终止后,程序才会终止。

Java 程序的终止是指除守护线程以外的线程全部终止。守护线程是执行后台作业的线程。我们可以通过 setDaemon 方法把线程设置为守护线程。

小知识

java.util.concurrent包中包含一个将线程创建抽象化的 ThreadFactory 接口。利用该接口,我们可以将 Runnable 作为传入参数并通过 new 创建 Thread 实例的处理隐藏在 ThreadFactory 内部。

Executors类中含有多种创建 ThreadFactory 的方法,感兴趣的可以去看一下源码

synchronized 相关

synchronized 方法

如果声明一个方法时,在前面加上关键字 synchronized 那么这个方法就只能由一个线程运行。只能由一个线程运行是每次只能由一个线程运行的意思,并不是说仅能让某一特定线程运行。这种方法叫做 synchronized,有时也称为同步方法。

synchronized void method() {
        ...
    }
复制代码

synchronized 代码块

如果只是想让方法中的某一部分由一个线程运行,而非整个方法,则可使用 synchronized 代码块

synchronized (表达式) {
        ...
    }
复制代码

synchronized 实例方法和 synchronized 代码块

假设有如下 synchronized 实例方法

synchronized void method() {
        ...
    }
复制代码

这跟下面将方法体用 synchronized 代码块包围起来是等效的

void method() {
    synchronized (this) {
        ...
    }
}
复制代码

synchronized 实例方法是使用 this 的锁来执行线程的互斥处理的

synchronized 静态方法和 synchronized 代码块

synchronized 静态方法和 synchronized 实例方法是相同的。但是 synchronized 静态方法使用的锁和 synchronized 实例方法使用的锁是不一样的

class Something {
    static synchronized void method() {
        ...
    }
}
复制代码

这跟下面将方法体用 synchronized 代码块包围起来是等效的

class Something {
    static void method() {
        synchronized (Something.class) {
            ...
        }
    }
}
复制代码

synchronized 静态方法是使用该类的类对象锁来执行线程的互斥处理的。 Something.class 是 Something 类对应的 java.lang.class 类的实例

wait、notify 和 notifyAll

等待队列

所有 实例 都拥有一个等待队列,它是在实例的 wait 方法执行后停止操作的线程队列。就好比为每个实例准备的线程休息室

在执行 wait 方法后,线程便会暂停操作,进入等待队列这个休息室。除非发生下列某一情况,否则线程会一直在等待队列中休眠。

  • 有其他线程的 notify 方法来唤醒线程
  • 有其他线程的 notifyAll 方法来唤醒线程
  • 有其他线程的 interrupt 方法来唤醒线程
  • wait 方法超时

若要执行 wait 方法, 线程必须持有锁 。但如果线程进入等待队列,便会释放其实例的锁

notify 方法

该方法会将等待队列中的一个线程去除。 同 wait 方法一样,若要执行 notify 方法,线程也必须持有要调用的实例的锁。

notify 唤醒的线程并不会在执行 notify 的一瞬间就重新运行。因为在执行 notify 的那一瞬间,执行 notify 的线程还持有着锁,所以其他线程还无法获取这个实例的锁

notifyAll 方法

notify 方法仅唤醒一个线程,而 notifyAll 则唤醒所有线程,这是两者之间唯一的区别

同 wait 方法和 notify 方法一样, notifyAll 方法也只能由持有要调用的实例锁的线程调用

notify 和 notifyAll 选择

notify 方法和 notifyAll 方法非常相似,到底该使用哪个?

实际上,这很难选择,由于 notify 唤醒的线程较少,所以处理速度要比使用 notifyAll 时快。 但使用 notify 时,如果处理不好,程序便可能会停止。 一般来说,使用 notifyAll 时的代码要比使用 notify 时的更为健壮。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

IT大败局

IT大败局

Merrill R.Chapman、周良忠 / 周良忠 / 电子工业出版社 / 2004-8-1 / 35.00

这是一本由作者亲身经历写就的MBA式教案。通过作者那专业人士的敏锐、活泼流畅的文笔和美国人特有的幽默,本书为我们剖析了IT界十个有代表性且影响深远的愚蠢败局。这十个败局涉及企业经营的十个主要方面,它们是:产业标准的魔力,“缩水”产品的阴霾,产品定位的泥潭,市场关系的教训,巨型企业的困惑,企业并购的陷阱,品牌战略的迷茫,技术导向的失衡,企业公关的真谛和科技虚幻的诱惑。 书中有许多鲜为人......一起来看看 《IT大败局》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具