黑马程序员技术交流社区
标题:
同步和互斥?
[打印本页]
作者:
↙五线谱╲
时间:
2013-10-31 19:42
标题:
同步和互斥?
在复习时,搜了下同步,又瞟到了互斥,
结果得知同步和互斥(不是异步)是有区别的,
再搜了些文档,同步和互斥更加纠结了,
那么我现在知道:
同步有协作关系,互斥有唯一性和排他性。
能来个些例子分析下吗?
虽然看了些解释,但还是觉得说的很模糊,那么求解:
两者的概念(或说是理解,通俗点啊)?
两者的区别?
我觉得视频中几个多线程的例子(同步的)是不是将同步和互斥都笼统的说成了同步了?
作者:
零下五度的水
时间:
2013-10-31 19:48
同步就是加锁,通常用在修改并读取数据的时候
异步就是不加锁,通常用在只读,或者只改并且没有上下限的时候
作者:
马晓平
时间:
2013-10-31 23:04
在实际应用中,多个线程往往会共享一些数据,并且各个线程之间的状态和行为是相互影响的。线程之间的影响有两种,一种是线程间的互斥,另一种是线程间的同步。
---线程安全(Thread-Safe)
---线程间的互斥
---线程间的同步
线程之间的关系大致可以分为两类
1、线程之间通过对资源的竞争,包括共享的数据和硬件资源,所产生的相互制约关系,这类线程间的主要问题是互斥和死锁问题,这类关系被称为互斥关系。
2、线程之间的相互协同合作,彼此之间直接知道对方的存在,并了解对方的名字,这类进程常常需要通过“进程间通信”方法来协同工作,这类关系被称为同步关系。
--共享资源是指在程序中并发运行的 若干个线程所操作的同一数据资源。
--并发运行的若干线程在操作共享资源时可能会出错,通常把这种现象称为非线程安全。反之,则称为线程安全
--线程间的互斥
出现共享资源访问冲突的实质是线程没有互斥的使用共享资源,即单个线程需要独占性的使用共享资源。
共享资源也称为“临界资源”,而将线程中访问共享变量的代码段称为临界段。为了使系统中并行线程正确而有效的访问资源,对线程互斥使用临界有以下原则:
1、在共享同一个临界资源的所有线程中,每次只允许有一个线程处于它的临界段之中。也就是说强制所有这些线程中,每次只允许其中的一个线程访问该共享变量。
2、线程只应在临界段内逗留有限时间。
3、若有多个线程同时要求进入它们的临界段时,就在有限的时间内让其中之一进入临界段,而不应相互阻塞,以至于各线程均无法进入临界段。
为了能够对临界段实现互斥,计算机科学家提出使用“同步愿语”来访问“信号量”的方式来解决。
信号量是指用于协调多个相互关联线程操作的信号,当一个线程需要访问临界段时,将被强制地停在临界段的访问入口处,直到收到一个专门的信号,才能进入临界段。
同步原语,通常用来保证临界段代码执行的原子性,即不可中断性。
Java中关键字 “synchronized”用于实现语句的同步操作,即给共享资源加互斥锁
锁定一个对象和一段代码
声明格式为:
synchronized(<对象名 >){
<语句组>
}
锁定一个方法
声明格式为:
synchronized<方法声明 >{
<方法体>
}
线程间的互斥
无论是对方法加互斥锁,还是对对象加互斥锁,其实质都是实现对共享资源的互斥访问
互斥操作是以降低应用程序的并发程度为代价的
因此,在编写多线程程序中,对synchronized的使用就遵循以下两个原则:
-不需要再多个线程中使用共享资源时,那么就没有必要使用该关键字;
-如果某个方法只是返回对象的值,而不去修改对象的值时,那么也就没有必要使用该关键字。
线程间的同步
从程序的运行结果可以看出存在二类错误:
Java中Object类提供了一组关于线程同步的方法
public final void wait(long timeout)
这个方法将使得执行该方法的线程对象被阻塞
注意Thread类的sleep方法和Object类的wait方法,均可以用于将线程的状态由运行状态转为不可运行状态,
但二者在等待时间上是有区别的,sleep()方法的等待时间是确定的,到时由系统唤醒,而wait方法的等待时间是不确定的,需要由线程通过notify()/notifyAll()方法来唤醒。
public final void notify()
唤醒被wait方法阻塞的单个线程
public final void notifyAll()
唤醒全被被wait方法阻塞的线程
小结:
线程的优先级
线程的优先级表示线程的重要程度
在默认条件下,一个线程将继承其父线程的优先级
线程优先级的使用原则与操作系统有着密切的联系因此在JAVA中的线程的调度是完全受其所运行平台的操作系统的线程调度程序控制的
可以使用getPriority()和setPriority()方法来获取与设定线程的优先级。
线程组
线程组提供了一个统一管理多个线程而不需要单独管理的机制
在JAVA语言中用java.lang,ThreadGroup类来支持线程组的实现
当多个线程分为一组时,可以用一个方法启动或挂起线程组中的所有线程
守护线程
守护线程,也称后台线程,是指在程序运行的时候在后台提供一种通用服务的线程
守护线程不会阻止程序的终止
使用setDaemon方法设定一个线程为守护线程。
要创建一个守护线程必须在调用它的start()方法之前设置
例子:模拟银行用户取钱的线程例子
public class MbankCompex { //模拟银行账户类
private static int sum = 2000;
public synchronized static void take(int k){ //限定take为同步方法
int temp = sum;
temp -= k;
try {
Thread.sleep((int)(100*Math.random()));}
catch (InterruptedException e) {}
sum = temp;
System.out.println(Thread.currentThread()+"sum = "+sum);
}
}
public class UserGetMoney extends Thread{ //模拟用户取款的线程类
public void run(){
for(int i=1;i<=4;i++){
MbankCompex.take(100);
}
}
}
public class BankAdvance { //调用线程的主类
public static void main(String[] args) {
UserGetMoney u1 = new UserGetMoney();
UserGetMoney u2 = new UserGetMoney();
u1.start();
u2.start();
}
}
作者:
黄炳期
时间:
2013-11-1 09:11
如果问题已经解决,请及时修改主题为“提问结束”
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2