您的位置:首页 > 编程语言

HIT软件构造 第十章 并发编程 进程 线程 线程安全

2019-05-28 11:06 281 查看

名词解释

  1. 进程(Process)和线程(thread):并发编程的两个基本单元。进程:(1)和同一个机器上的其他进程是彼此隔离的。(2)拥有私有的内存空间,运行时不能共享变量。(3)通过IPC(pipe/socket)进行通信。线程:(1)共享所在进程的内存空间(2)共享可变对象的共享时,需要同步(使用synchronization关键字维护线程安全)。(3)有独立的运行时栈,就像一个普通的函数。(4)杀死线程不安全。
  2. Concurrent(并发):在单核机器上,“多进程”并不是真正的多个进程在同时执行,而是通过CPU时间分片,操作系统快速在进程间切换而模拟出来的多进程。(此处默认是一个cpu只有一个核心)
    与并行的区别:在多核机器上,一个CPU执行一个任务,这些任务之间是并行。
  3. 时间分片(time slicing):处理器在不同的线程之间进行切换。
  4. 交错(interleaving):两个程序被转换为机器指令集A和B,A和B的元素(cpu指令)交替执行。
  5. 竞争(race condition):A和B是两个线程,A和B执行的交错会影响程序的正确性。
  6. 消息传递(message passing):模块之间进行信息传递。
  7. 线程安全(thread safe):ADT或方法在多线程中要执行正确 (不违反spec、保持RI ;与多少处理器、 OS如何调度线程;不会使spec增强)
  8. 限制共享(Confinement):线程之间不共享mutable数据类型(在线程内部使用局部变量,如果一个局部变量是一个对象引用,那么需要检查有没有在其他的线程中进行引用)(这个规则要求避免使用全局变量)。

关键问题

  1. 并发编程的两个程序之间如何进行交互?
    (1)进行内存共享(shared memory)
    两个处理器进行内存共享(运行时ADT)
    两个程序访问一样的文件系统
    两个线程,共享Java对象
    (2)进行信息传递(message passing)
    两台机器,通过网络通讯
    同一台计算机上的两个程序,通过管道(ls|grep)连接进行通讯。
  2. 为什么要进行多线程编程呢?
    为了充分利用cpu多核的特性(就是不让cpu的核心闲置,每一个特定时间只执行一个线程,就失去了多核的意义)。
  3. 为什么不能杀死线程呢?
    会让共享data陷入不确定状态(因为线程之间是共享数据的,而且你杀死线程的时候也不知道这个线程是运行到了哪里)。
  4. 线程安全的四种操作是什么?
    限制数据共享,共享不可变数据,共享线程安全的可变数据,采取同步机制(变并行为串行)。
  5. 在线程安全的四种操作中,他们之间控制的范围是不是有重叠呢?
    没有,限制数据共享说的是ADT没有rep的时候,也就是最原始的情况;如果你想用immutable类型的rep,那么就是策略二的范围了,共享不可变数据,也就是你的rep前面加一个final(当然是举个例子,还有其他方法);如果一定要使用mutable的数据类型,那么就使用java API(与synchronizedCollection有关),但是在这样的API上,使用iterator也是不安全的。
  6. immutability的定义呢?
    没有mutator方法,所有的rep都是private和final的,没有表示泄露,没有mutation(像beneficent mutation这样的也不行),不允许子类重写方法。

关键操作

  1. 开启一个线程(两种方法)
    (1)从Thread类派生子类
    重写thread的run方法,调用start方法
public class HelloThread extends Thread {
public void run() {
//在这里加入你想要实现的内容
}
}
public static void main(String args[]) {
(new HelloThread()).start();
}

(2)从Runnable接口构造Thread对象
实现runna接口,将一个新的实例传给thread的构造函数,调用的新的thread实例的start方法

public class HelloRunnable implements Runnable {
public void run() {
//在这里加入你想要实现的内容
}
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
  1. 使用一些方法影响线程之间的interleaving关系
    Thread.sleep() 进入休眠的线程不会失去对现有monitor或锁的所有权。
    Thread.interrupt() 会向Thread发送信号,但是只有在thread在sleep的时候才会接受interrupt信号,发送的信号如果没有被接受会保留,知道遇到sleep,interrupted或者线程结束。
    Thread.interrupted() 检测有没有interrupt信号。
    Thread.yield() 在run方法中调用,将cpu的控制权交出。
    join() 阻塞线程。

知识point

  1. Java虚拟机只运行单一进程(可以创建进程)。
  2. java.util.concurrent是java并发包。
  3. 多线程和多进程之间共享处理器是通过时间分片完成的。
  4. 时间分片是OS自动调度的,也就是说一个正在执行的线程随时可能暂停,随时可能重新开始。
  5. 在多线程的任务中,因为共享memory,所以交错有可能造成错误。
  6. 交错产生错误的结果指的是违反了后置条件和不变量。
  7. 单行、单挑语句都未必是原子的,是否原子,由JVM确定 。
  8. 消息传递的时候的消息队列必须是java程序,不是原子操作。
  9. 消息传递机制无法解决竞争条件问题 。
  10. sleep,interrupted,join都会检测线程是否收到interrupt信号。
  11. iterator不是线程安全的。
  12. java不会保证一个线程中发生的assignment会立即被另外一个线程看到,他有可能被临时地存储起来。
  13. HashMap是线程不安全的,因为put方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: