分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

synchronized:解决死锁的问题[轉貼]
最近对pv操作研究了一下,才发现原来java已经提供了内置的防死锁功能,不能不说它是很人性的了。下面就是整理的资料:
 
多线程的互斥与同步
 
临界资源问题
 
前面所提到的线程都是独立的,而且异步执行,也就是说每个线程都包含了运行时所需要的数据或方法,而不需要外部的资源或方法,也不必关心其它线程的状态或行为。但是经常有一些同时运行的线程需要共享数据,此时就需考虑其他线程的状态和行为,否则就不能保证程序的运行结果的正确性。例说明了此问题。
 
class stack{
int idx=0; //堆栈指针的初始值为0
char[ ] data = new char[6]; //堆栈有6个字符的空间
 
public void push(char c){ //压栈操作
data[idx] = c; //数据入栈
idx + +; //指针向上移动一位
}
 
public char pop(){ //出栈操作
idx - -; //指针向下移动一位
return data[idx]; //数据出栈
}
}
 
 
两个线程A和B在同时使用Stack的同一个实例对象,A正在往堆栈里push一个数据,B则要从堆栈中pop一个数据。如果由于线程A和B在对Stack对象的操作上的不完整性,会导致操作的失败,具体过程如下所示:
 
1) 操作之前
data = | p | q | | | | | idx=2
 
 
2) A执行push中的第一个语句,将r推入堆栈;
data = | p | q | r | | | | idx=2
 
3) A还未执行idx++语句,A的执行被B中断,B执行pop方法,返回q:
data = | p | q | r | | | | idx=1
 
4〕A继续执行push的第二个语句:
data = | p | q | r | | , | | idx=2
最后的结果相当于r没有入栈。产生这种问题的原因在于对共享数据访问的操作的不完整性。
 
互斥锁
 
为解决操作的不完整性问题,在Java 语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问。
 
public void push(char c){
synchronized(this){ //this表示Stack的当前对象
data[idx]=c;
idx++;
}
}
public char pop(){
synchronized(this){ //this表示Stack的当前对象
idx--;
return data[idx];
}
}
 
 
 
synchronized 除了象上面讲的放在对象前面限制一段代码的执行外,还可以放在方法声明中,表示整个方法为同步方法。
public synchronized void push(char c){
}
 
如果synchronized用在类声明中,则表明该类中的所有方法都是synchronized的。
 
 
 
多线程的同步
 
本节将讨论如何控制互相交互的线程之间的运行进度,即多线程之间的同步问题,下面我们将通过多线程同步的模型: 生产者-消费者问题来说明怎样实现多线程的同步。
 
我们把系统中使用某类资源的线程称为消费者,产生或释放同类资源的线程称为生产者。
在下面的Java的应用程序中,生产者线程向文件中写数据,消费者从文件中读数据,这样,在这个程序中同时运行的两个线程共享同一个文件资源。通过这个例子我们来了解怎样使它们同步。
 
 
class SyncStack{ //同步堆栈类
private int index = 0; //堆栈指针初始值为0
private char []buffer = new char[6]; //堆栈有6个字符的空间
 
public synchronized void push(char c){ //加上互斥锁
while(index = = buffer.length){ //堆栈已满,不能压栈
try{
this.wait(); //等待,直到有数据出栈
}catch(InterruptedException e){}
}
 
this.notify(); //通知其它线程把数据出栈
buffer[index] = c; //数据入栈
index++; //指针向上移动
}
 
public synchronized char pop(){ //加上互斥锁
while(index ==0){ //堆栈无数据,不能出栈
try{
this.wait(); //等待其它线程把数据入栈
}catch(InterruptedException e){}
}
 
this.notify(); //通知其它线程入栈
index- -; //指针向下移动
return buffer[index]; //数据出栈
}
}
 
class Producer implements Runnable{ //生产者类
SyncStack theStack;
//生产者类生成的字母都保存到同步堆栈中
 
public Producer(SyncStack s){
theStack = s;
}
 
public void run(){
char c;
for(int i=0; i<20; i++){
c =(char)(Math.random()*26+'A');
//随机产生20个字符
theStack.push(c); //把字符入栈
System.out.println("Produced: "+c); //打印字符
try{
Thread.sleep((int)(Math.random()*1000));
/*每产生一个字符线程就睡眠*/
}catch(InterruptedException e){}
}
}
}
 
class Consumer implements Runnable{ //消费者类
SyncStack theStack;
//消费者类获得的字符都来自同步堆栈
 
public Consumer(SyncStack s){
theStack = s;
}
 
public void run(){
char c;
for(int i=0;i<20;i++){
c = theStack.pop(); //从堆栈中读取字符
System.out.println("Consumed: "+c);
//打印字符
try{
Thread.sleep((int)(Math.random()*1000));
/*每读取一个字符线程就睡眠*/
}catch(InterruptedException e){}
}
}
}
 
public class SyncTest{
public static void main(String args[]){
SyncStack stack = new SyncStack();
//下面的消费者类对象和生产者类对象所操作的是同一个同步堆栈对象
Runnable source=new Producer(stack);
Runnable sink = new Consumer(stack);
Thread t1 = new Thread(source); //线程实例化
Thread t2 = new Thread(sink); //线程实例化
t1.start(); //线程启动
t2.start(); //线程启动
}
}
 
类Producer是生产者模型,其中的 run()方法中定义了生产者线程所做的操作,循环调用push()方法,将生产的20个字母送入堆栈中,每次执行完push操作后,调用sleep()方法睡眠一段随机时间,以给其他线程执行的机会。类Consumer是消费者模型,循环调用pop()方法,从堆栈中取出一个数据,一共取20次,每次执行完pop操作后,调用sleep()方法睡眠一段随机时间,以给其他线程执行的机会。
 
程序执行结果
Produced:V
Consumed:V
Produced:E
Consumed:E
Produced:P
Produced:L
...
Consumed:L
Consumed:P
 
在上述的例子中,通过运用wait()和notify()方法来实现线程的同步,在同步中还会用到notifyAll()方法,一般来说,每个共享对象的互斥锁存在两个队列,一个是锁等待队列,另一个是锁申请队列,锁申请队列中的第一个线程可以对该共享对象进行操作,而锁等待队列中的线程在某些情况下将移入到锁申请队列。下面比较一下wait()、notify()和notifyAll()方法:
 
(1) wait,nofity,notifyAll必须在已经持有锁的情况下执行,所以它们只能出现在synchronized作用的范围内,也就是出现在用  synchronized修饰的方法或类中。
 
(2) wait的作用:释放已持有的锁,进入等待队列.
(3) notify的作用:唤醒wait队列中的第一个线程并把它移入锁申请队列.
 
(4) notifyAll的作用:唤醒wait队列中的所有的线程并把它们移入锁申请队列.
 
注意:
1) suspend()和resume()
在JDK1.2中不再使用suspend()和resume(),其相应功能由wait()和notify()来实现。
 
2) stop()
在JDK1.2中不再使用stop(),而是通过标志位来使程序正常执行完毕。例6.6就是一个典型的例子。
 
public class Xyz implements Runnable {
private boolean timeToQuit=false; //标志位初始值为假
public void run() {
while(!timeToQuit) {//只要标志位为假,线程继续运行
}
}
 
public void stopRunning() {
timeToQuit=true;} //标志位设为真,表示程序正常结束
}
public class ControlThread {
private Runnable r=new Xyz();
private Thread t=new Thread(r);
public void startThread() {
t.start();
}
public void stopThread() {
r.stopRunning(); }
//通过调用stopRunning方法来终止线程运行
}

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

synchronized 解决死锁的问题 轉貼相关推荐

  1. 面试官:谈谈什么是死锁?如何解决死锁?

    死锁就是有一天你回家,拿着一把钥匙使劲往锁眼里面捅,结果钥匙断里面了,所以你就叫开锁师傅要开锁,结果锁给开死了,这就是死锁了.以上仅仅是玩笑话,以下步入正题. 什么是死锁? 要了解什么是死锁,要首先明 ...

  2. 一个多线程死锁案例,如何避免及解决死锁问题?

    多线程死锁在java程序员笔试的时候时有遇见,死锁概念在之前的文章有介绍,大家应该也都明白它的概念,不清楚的去翻看历史文章吧. 下面是一个多线程死锁的例子 public class lock{priv ...

  3. 什么叫死锁?死锁案例?死锁必须满足哪些条件?如何定位死锁问题?有哪些解决死锁策略?哲学家问题?

    1.死锁是什么? 死锁一定发生在并发环境中,死锁是一种状态,当两个(或者多个线程)相互持有对方所需要的资源,却又都不主动释放手中持有的资源,导致大家都获取不到自己想要的资源,所有相关的线程无法继续执行 ...

  4. Java多线程学习四十二:有哪些解决死锁问题的策略和哲学家就餐问题

    线上发生死锁应该怎么办 如果线上环境发生了死锁,那么其实不良后果就已经造成了,修复死锁的最好时机在于"防患于未然",而不是事后补救.就好比发生火灾时,一旦着了大火,想要不造成损失去 ...

  5. (轉貼)《程序员》推荐C++ 图书三人谈 (C/C++)

    轉貼自http://bbs.cnitexam.com/simple/index.php?t22602.html 主持人:熊节(透明),<程序员>杂志编辑,C-View成员 嘉   宾:孟岩 ...

  6. (轉貼) 千頭萬緒 : 學習多執行緒程式設計的好書 (.NET) (Java)

    轉貼自千頭萬緒 : 學習多執行緒程式設計的好書 找對書,多執行緒不再避之唯恐不及 科學家對於人類大腦的運作方式,目前仍存在許多爭議.但是許多經過科學實驗的證據顯示,人類的大腦是以平行的方式工作.即使如 ...

  7. (轉貼) 大年三十整理的asp.net资料! (.NET) (ASP.NET)

     大年三十整理的asp.net资料! 使用SqlBulkCopy类加载其他源数据到SQL表 在数据回发时,维护ASP.NET Tree控件的位置 vagerent的vs2005网站开发技巧 ASP.N ...

  8. java死锁_Java死锁原理,手写死锁,解决死锁

    死锁:多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能进行,而导致两个或者多个线程都在等在对方释放资源. 都停止的情形.某一个同步块同时拥有两个以上对象的锁时,就会产生死锁问题. 手写 ...

  9. 死锁、活锁、饥饿定位死锁解决死锁

    文章目录 1. 死锁 2. 定位死锁 2.1 jstack工具使用 2.2 jconsole工具使用: 3. 解决死锁 3.1 哲学家就餐问题 4. 活锁 4.1 活锁原因 4.2 活锁解决 5. 饥 ...

最新文章

  1. python 命令行参数-python中命令行参数
  2. ios开发,地图标注聚集。搜索标注title功能
  3. tableau应用实战案例(五十)-销售业绩的tableau可视化案例
  4. php 转换数组的字符集,PHP 自动转换字符集(支持字符串和数组)功能实例
  5. Study 4 —— 数据类型(1)
  6. 网易云信自研大规模传输网核心系统架构剖析
  7. hive 两个没有null指定的表左关联的结果有null_《数据仓库篇》——Hive的学习笔记3...
  8. 半圆和圆锥在一起会产生什么神奇的反应?
  9. 工业级光纤收发器使用“避坑”指南
  10. 康奈尔机器人的肌肉是爆米花做的,果然很有爆发力 | ICRA 2018
  11. [转]-Sublime Text 3最好的功能、插件和设置
  12. in packet sniffer
  13. 佳能MP258mp259清零软件
  14. Vue路由SPA介绍
  15. 数字钟Matlab仿真,简单数字钟仿真电路图大全(五款数字钟仿真电路图) - 全文...
  16. 软件工程毕业设计课题(80)微信小程序毕业设计PHP电影视频播放小程序系统设计与实现
  17. idea创建maven项目失败, Failed to create a Maven project
  18. POJ 1419-Graph Coloring
  19. 炒菜机器人放食材的顺序_九阳发布了一堆厨电:要用“进化”颠覆人类的饮食、厨房生活...
  20. 梁漱溟:做学问的八个境界

热门文章

  1. 让 AI “潜入”物流中心,你的快递很快就到!
  2. 补习系列(20)-大话 WebSocket 与 尬聊的实现
  3. Flask自定义时间过滤器
  4. 一统江湖的大前端(2)—— Mock.js + Node.js 如何与后端潇洒分手
  5. 使用inspector功能查看和管理契约
  6. 基于 Kata Containers 与 iSulad 的云容器实践解析
  7. python机器学习2021年6月19日09:35:06
  8. python查看list_reverseiterator object中的内容
  9. sob攻略超详细攻略_2020云南旅游超详细必看攻略(附带云南美食景点攻略)
  10. source:读取文件 “/etc/profile” 时发生错误解决办法