[align=center][size=large][b]Java中的线程同步小结[/b][/size][/align]
最近听了大家讲一些线程同步的知识,个人感觉只学到了一些皮毛,以前也写过有关线程的小程序,但没想这么多,像神马线程同步问题的。。。在这里就跟大家来分享一下我这两天学到的一点东西吧。个人很菜。还望各位大神路过飘过的多多指教昂。。。
[size=medium][b]什么是线程同步?[/b][/size]
[size=small]“线程同步”刚接触到这个名词时,顾名思义,就是多个线程一起跑的意思咯。其实不然昂。恰恰相反。线程同步就是各个线程为了竞争同一互斥资源而产生的。当一个资源必须互斥使用时,那么此时的线程就不能一窝蜂的全上,必须排队等待使用这段资源。于是就产生了线程同步。实际上就是各个线程排队等待一段临界资源的问题(需注意的是:这段资源必须是共享的,若不是共享的就没有同步的必要了)。[/size]
[size=medium][b]为什么要进行线程同步?[/b][/size]
[size=small]线程给我们带来了很多好处,但是由于线程可以执行程序中的任意代码段,而且线程的运行是有java虚拟机控制的。所以就不避免出现多个线程对同一资源的操作,产生错误。比如:现有一银行账户里有1000元,一人拿存折去柜台取,另一人到自动取款机取。则这两个人就相当于两个线程,账户则是临界资源。若它们之间不同步进行,那银行就亏大发了。。。[/size]
[size=medium][b]Java中如何实现多线程同步的?[/b][/size]
[size=small]多线程的线程同步机制实际上是靠锁来实现的,在java中常用到关键字synchronized(同步的),使用synchronized块或者synchronized方法是标志一个监视区域,当每次进入一个监视区域时,java虚拟机都会自动锁上对象或者类,我们不需要自己动手加锁,对象锁是java虚拟机内部使用的。当线程运行到有synchronized修饰的程序段时,会先检查是否有线程在运行它,否则就排队等待,只有当没有线程使用它的时候才能运行该段程序,一旦进入后就独占这段资源直到其释放结束。[/size]
[size=medium][b]Synchronized关键字:[/b][/size]
[size=small]不同实例中的synchronized方法是互不干扰的。其他线程照样可以访问相同类的其他实例对象中的synchronized方法
Synchronized可以定义一个锁定方法或者一个程序块。具体表现为:
Synchronized(同步锁){
//需要同步执行的代码
}
注意--->synchronized(object){}object要是同一个锁对象
举个例子可能会表达的清楚一点[/size]
[/size][size=medium][b]生产/消费者模型:[/b][/size]
[size=small]仅仅使用上面所说的同步锁往往不能满足实际需求,当我们的一个线程在运行的时候需要等待使用另外一个线程的结果才能继续执行,那么就要用到生产/消费者模型了。简单的来说,A负责向容器C中放入元素,条件是容器C为空的时候。而B需要从容器中取走一个元素,条件自然就是C不为空。就相当于一个“等待/通知”模型了。比如:[/size]
[size=small]这里需要注意wait()和notify()/notifyAll():
wait()和notify()/notifyAll()都是Object类下的方法,也就是说所有的类都有这三个方法,因为这一方法在阻塞时要释放其占用的锁,而锁是任意对象都有的,当对象调用wait()时就进入等待队列,并释放该对象占有的锁。
Wait():它与线程的sleep方法不同,sleep是线程类的一个方法,使线程进入阻塞状态,没有得到CPU时间,但没有释放该线程占用的资源,它依然保存着锁,别的线程就进不来。而wait就相当于该线程放弃了自己已占用的资源,使自己进入等待状态,直到收到通知notify后再重新竞争资源。运行时要捕捉一个异常IllegalMonitorStateException。
Notify()/notifyAll():负责唤醒某个处于等待队列的线程,要说具体唤醒哪个线程则是不确定的,是又JVM负责,注意这里并不与线程本身的优先级有关。notifyAll()与notify()的唯一区别就是notifyAll()解除了所有因调用了本身wait方法而处于等待状态的线程,最终都是只有那个获得锁的使用权的线程才能开始执行。[/size]
最近听了大家讲一些线程同步的知识,个人感觉只学到了一些皮毛,以前也写过有关线程的小程序,但没想这么多,像神马线程同步问题的。。。在这里就跟大家来分享一下我这两天学到的一点东西吧。个人很菜。还望各位大神路过飘过的多多指教昂。。。
[size=medium][b]什么是线程同步?[/b][/size]
[size=small]“线程同步”刚接触到这个名词时,顾名思义,就是多个线程一起跑的意思咯。其实不然昂。恰恰相反。线程同步就是各个线程为了竞争同一互斥资源而产生的。当一个资源必须互斥使用时,那么此时的线程就不能一窝蜂的全上,必须排队等待使用这段资源。于是就产生了线程同步。实际上就是各个线程排队等待一段临界资源的问题(需注意的是:这段资源必须是共享的,若不是共享的就没有同步的必要了)。[/size]
[size=medium][b]为什么要进行线程同步?[/b][/size]
[size=small]线程给我们带来了很多好处,但是由于线程可以执行程序中的任意代码段,而且线程的运行是有java虚拟机控制的。所以就不避免出现多个线程对同一资源的操作,产生错误。比如:现有一银行账户里有1000元,一人拿存折去柜台取,另一人到自动取款机取。则这两个人就相当于两个线程,账户则是临界资源。若它们之间不同步进行,那银行就亏大发了。。。[/size]
[size=medium][b]Java中如何实现多线程同步的?[/b][/size]
[size=small]多线程的线程同步机制实际上是靠锁来实现的,在java中常用到关键字synchronized(同步的),使用synchronized块或者synchronized方法是标志一个监视区域,当每次进入一个监视区域时,java虚拟机都会自动锁上对象或者类,我们不需要自己动手加锁,对象锁是java虚拟机内部使用的。当线程运行到有synchronized修饰的程序段时,会先检查是否有线程在运行它,否则就排队等待,只有当没有线程使用它的时候才能运行该段程序,一旦进入后就独占这段资源直到其释放结束。[/size]
[size=medium][b]Synchronized关键字:[/b][/size]
[size=small]不同实例中的synchronized方法是互不干扰的。其他线程照样可以访问相同类的其他实例对象中的synchronized方法
Synchronized可以定义一个锁定方法或者一个程序块。具体表现为:
Synchronized(同步锁){
//需要同步执行的代码
}
注意--->synchronized(object){}object要是同一个锁对象
举个例子可能会表达的清楚一点[/size]
public static final Object ob=new Object();//生成一个同步锁对象
F1(){
Synchronized(ob){
//代码A
//访问共享资源,需要同步
}}
F2(){
Synchronized(ob){
//代码B
//访问同一个共享资源,需要同步
}}
[size=small]假设现在有10个线程竞争代码A,10个线程竞争代码B,而他们都得竞争同一个锁(ob),同一时刻,只有一个线程能获得锁ob的使用权,而其他的线程就只能排队等待了,进入线程的就绪队列。
[/size][size=medium][b]生产/消费者模型:[/b][/size]
[size=small]仅仅使用上面所说的同步锁往往不能满足实际需求,当我们的一个线程在运行的时候需要等待使用另外一个线程的结果才能继续执行,那么就要用到生产/消费者模型了。简单的来说,A负责向容器C中放入元素,条件是容器C为空的时候。而B需要从容器中取走一个元素,条件自然就是C不为空。就相当于一个“等待/通知”模型了。比如:[/size]
// 锁定同一个对象
synchronized (this.dataList) {
//获得锁控制权后执行代码
while (dataList.size() > 0) {//若队列中存在元素,则进入等 待队列
try {
dataList.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} while(dataList.size() == 0) {
this.count++;
data dt = new data();//data是要放入的数据对象
dt.id = count;
dt.name = "气球";
dataList.add(dt);
System.out.println("队列中加入了" + dt.toString());
try {
Thread.sleep(1000);
} catch (Exception ex) {
ex.printStackTrace();
}
// 加入新元素后通知消费者
dataList.notify();
}
}
[size=small]这里需要注意wait()和notify()/notifyAll():
wait()和notify()/notifyAll()都是Object类下的方法,也就是说所有的类都有这三个方法,因为这一方法在阻塞时要释放其占用的锁,而锁是任意对象都有的,当对象调用wait()时就进入等待队列,并释放该对象占有的锁。
Wait():它与线程的sleep方法不同,sleep是线程类的一个方法,使线程进入阻塞状态,没有得到CPU时间,但没有释放该线程占用的资源,它依然保存着锁,别的线程就进不来。而wait就相当于该线程放弃了自己已占用的资源,使自己进入等待状态,直到收到通知notify后再重新竞争资源。运行时要捕捉一个异常IllegalMonitorStateException。
Notify()/notifyAll():负责唤醒某个处于等待队列的线程,要说具体唤醒哪个线程则是不确定的,是又JVM负责,注意这里并不与线程本身的优先级有关。notifyAll()与notify()的唯一区别就是notifyAll()解除了所有因调用了本身wait方法而处于等待状态的线程,最终都是只有那个获得锁的使用权的线程才能开始执行。[/size]