java多线程同步与死锁_线程同步、死锁和通信——Java多线程(二)

一、多线程同步

上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题。

1.同步代码块

1 class RunnableDemo implementsRunnable2 {3 private int tickets=5;4 public voidrun()5 {6 while(true)7 {8 synchronized(this)//同步代码块语法定义如下9 {10 if(tickets<=0) break;11 try{12 Thread.sleep(100);13 }14 catch(Exception e){15 e.printStackTrace();16 }17 System.out.println(Thread.currentThread().getName()+"出售票:"+tickets);18 tickets -= 1;19 }20 }21 }22 }23

24 public classThreadTest25 {26 public static voidmain(String[] args)27 {28 RunnableDemo r = newRunnableDemo();29 newThread(r).start();30 newThread(r).start();31 newThread(r).start();32 newThread(r).start();33 }34 }

在同一时刻只能由一个线程进入同步代码块内运行,只有当该线程离开同步代码块后,其他线程才能进入同步代码块内运行。

2.同步方法

即:把上述例子中同步代码块的内容,专门封装在一个方法里,通过在run()方法中调用创建的方法实现相应的功能。

1 class RunnableDemo implementsRunnable2 {3 private int tickets=5;4 public voidrun()5 {6 while(tickets>0)7 {8 sale();9 }10 }11 public synchronized void sale()//同步方法12 {13 if(tickets>0){14 try{15 Thread.sleep(100);16 }17 catch(Exception e){18 e.printStackTrace();19 }20 System.out.println(Thread.currentThread().getName()+"出售票:"+tickets);21 tickets -= 1;22 }23 }24 }25

26 public classThreadTest27 {28 public static voidmain(String[] args)29 {30 RunnableDemo r = newRunnableDemo();31 newThread(r).start();32 newThread(r).start();33 newThread(r).start();34 newThread(r).start();35 }36 }

二、死锁

如果有一组进程(或线程),线程1 已经占据资源R1,并持有资源R1上的锁,而且正在等待资源R2开锁;线程2已经占据资源R2,并拥有资源R2上的锁,却正在等待R1开锁。那么这两个线程都不释放自己占据的资源,同时申请不到对方资源上的锁,它们只能永远等待下去。这种现象就叫做死锁。

预防死锁的一种方法:利用有序资源分配策略——要求线程申请资源必须按照以编号上升的次序依次申请。

三、线程间通信

同属于一个进程的多个线程,是共享地址空间的,它们可以相互通信,共同协作来完成指定任务。

Java是通过Object类的wait()、notify()、notifyAll()这几个方法来实现线程间的通信。

wait():线程进入睡眠状态,直到其他线程进入并调用notify()或notifyAll()为止。

notify():唤醒在该同步代码块中第1个调用wait()的线程。

notifyAll():唤醒在该同步代码块中所有调用wait()的线程,高优先级最先被唤醒。

1 class Producer implementsRunnable2 {3 Person q = null;4 publicProducer(Person q)5 {6 this.q=q;7 }8 @Override9 public voidrun()10 {11 for(int i=0;i<10;i++)12 {13 if(i%2==0)14 {15 q.set("张三","男");16 }17 else{18 q.set("李四","女");19 }20 }21 }22 }23 class Consumer implementsRunnable24 {25 Person q = null;26 publicConsumer(Person q)27 {28 this.q=q;29 }30 @Override31 public voidrun()32 {33 for(int i=0;i<10;++i)34 {35 q.get();36 }37 }38 }39 classPerson40 {41 private String name = "李四";42 private String sex = "女";43 private boolean bFull = false;//当Consumer线程取走数据后,false

44 public synchronized voidset(String name,String sex)45 {46 if(bFull)47 {48 try

49 {50 wait();//后来的线程要等待

51 }catch(InterruptedException e){52 e.printStackTrace();53 }54 }55 this.name =name;56 this.sex =sex;57 bFull = true;//当Producer线程放入数据后,true

58 notify();//唤醒最先到达的线程

59 }60 public synchronized void get()61 {62 if(!bFull)63 {64 try{65 wait();66 }catch(InterruptedException e){67 e.printStackTrace();68 }69 }70 System.out.println(name+"——>"+sex);71 bFull = false;72 notify();73 }74 }75 public classThreadCommunation76 {77 public static voidmain(String[] args)78 {79 Person q = newPerson();80 new Thread(newProducer(q)).start();81 new Thread(newConsumer(q)).start();82 }83 }

***注意:wait()、notify()、notifyAll()这三个方法必须在synchronized方法中调用,该线程必须得到该对象的所有权。

四、线程的生命周期

控制线程生命周期的方法:suspend()、resume()、stop()方法,但是这三个方法都不推荐使用。

若想控制线程的生命周期,推荐使用在run()方法中添加循环条件的方法来实现对线程生命周期的控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值