线程的同步
文章来自 shichang // Welcome!
主页
|
About Me
|
归档
|
标签
为了实现数据的共享,资源的合理分配,进程之间也必须要进行同步。线程的同步更是为了消除线程之间的不确定性,使得整个程序的运行和正确性都有迹可循,提高CPU的执行效率。 ### 加锁: 将资源加锁保证同一时刻只能有一个线程在访问和修改资源 ### 互斥 不能有两个进程同时在临界区中, 进程能够在任何数量和速度的CPU上正确执行, 在互斥区域外不能阻止另一个进程的运行, 进程不能无限制地等待进入临界区 ### 睡眠操作: 为了避免一个线程在阻塞时浪费cpu资源,所以规定了睡眠和唤醒机制,线程在遇见阻塞时进行睡眠,让出cpu资源,当其他线程代码从临界区退出时发送信号唤醒睡眠的线程。 <br> ### 信号量: 为了避免两个线程同时睡眠,形成死锁,所以使用信号量将发出的信号累积起来。信号量就是一个计数器,取值为当前积累的信号数量,支持up加和down减两种操作。两个操作都是原子操作。 如果用0和1作为信号量的取值,则为二元信号量。 down减法操作: - 等待信号量的值变为1 - 将信号量的值设置为0 - 继续往下执行 up加法操作: - 将信号量的值设置为1 - 叫醒在该信号量上面等待的第一个线程 - 线程继续往下执行 但是信号量并不是这么好用的东西,对一个进程来说,往往需要非常多个信号量才能保证程序按正确的顺序运行,而当信号量数量多了之后程序就变得非常难以书写和维护。 所以在此1引入了**管程**的概念, ### 管程 管程是一个程序语言级别的构造,它的正确性由编译器负责保证。将需要同步的代码用一个管程的构造框起来,获得同步保护,管程就是一组子程序、变量和数据结构的组合。 管程中使用两种同步机制:锁和条件变量,锁用来互斥,条件变量用来控制执行的顺序。 ### 锁,睡眠唤醒,信号量,管程,消息传递之间的关系 `锁`解决了同步问题(金鱼喂养问题),但是会造成循环等待,等待时浪费了大量的CPU,所以使用`睡眠和唤醒`机制使进程或者线程在等待时让出cpu进行睡眠直到其所等待的资源被让出并唤醒该进程或者线程。但是睡眠和唤醒机制又带来了死锁问题,死锁问题就是互相竞争的两个进程同时进行了睡眠(进程在执行sleep之前有可能发生cpu的切换,造成过早无效唤醒,而收到唤醒消息后原进程再进行sleep就没有其他进程再会视图唤醒它,另一个进程在执行到进度后也会进行睡眠,造成死锁)。为了不让互相竞争的两个进程同时睡眠,所以需要将信号累积起来,就使用了`信号量`的概念,将睡眠和唤醒的信号抽象成一个状态值,当这个值存在即表示一个信号,成功唤醒或者睡眠一个,这个状态值就加1或者减1.这样两个进程就不会同时睡觉了。但信号量的数量多了以后程序变得非常难以管理和书写,所以引入`管程`的概念。管程保证管程内部的线程和资源同步,由编译器进行保证管程的实现。但是管程只能在单台计算机上发挥作用,如果需要在多计算机上进行同步,则需要`消息传递`,基本操作为send和receive,都是阻塞操作。而消息传递的问题在于消息丢失和身份识别,还有效率。由于网络的不可靠,即使是TCP协议也无法做到100%的可靠,所以只有尽量采取更加可靠的传输协议,身份识别可以使用数字签名和加密技术进行弥补
Pre:
Java线程安全
Next:
mysql 索引,视图,数据导入导出,备份和恢复