synchronized、wait、notify、notifyAll
2016-07-02 11:44
447 查看
因为同一个进程的线程之间可以共享同一个进程空间,所以实现线程的数据共享是很容易的(当然在并发中实现数据结构的一致性则另当别论),也可以使用管道流来进行线程通信(没必要)。此处只说协调控制机制
synchronized、wait、notify、notifyAll
使用Java语言内置关键字synchronized来进行加锁,可以保证任务执行的可见性和原子性,从而实现同步执行。synchronized关键字使用的是对象锁,锁的实现依附于对象,避免了锁的创建,所以接下来就直接默认synchronized就是对对象加锁,便于理解。使用方式上,可以显式对对象加锁synchronized(obj){},也可以隐式对当前对象加锁,就是所谓的同步方法或者synchronized(this){}代码块。这里多说一句,因为synchronized是依附对象的加锁策略,所以在普通方法上加synchronized修饰,加锁范围是当前类的实例,对静态方法上加synchronized修饰,加锁范围为Class类实例,两者属于不同对象,所以不存在竞争问题。
调用对象的wait方法,使当前线程进入阻塞状态,直到被notify、notifyAll唤醒。notify、notifyAll方法属于大范围无差别唤醒策略,当前进程空间内的所有调用wait进入阻塞状态的线程都可能响应,没有针对性。
生产者消费者示例
这里说一下,生产者线程判断buf不满使用的检查条件是while(buf.isFull()){},这里使用while循环而不是if判断。因为当某一个消费者线程con调用了notify后,会有某个因为wait而阻塞的生产者线程pro被唤醒,但是此时con仍然占据锁,需要等con代码块执行完毕,释放锁后,pro获得锁开始执行,如果con脑袋秀逗了,notify后,加了一句buf.put(new
Object()),则pro在if语句的wait醒来后,直接向下执行,可能抛出越界异常。
总结
Synchronized、wait、notify、notifyAll可以实现一定程度的线程协调作用,但是在灵活性方面做的不好,引入Lock、Condition可以在一方面弥补这些缺陷,当然API层次的locks包也有不足。
synchronized、wait、notify、notifyAll
使用Java语言内置关键字synchronized来进行加锁,可以保证任务执行的可见性和原子性,从而实现同步执行。synchronized关键字使用的是对象锁,锁的实现依附于对象,避免了锁的创建,所以接下来就直接默认synchronized就是对对象加锁,便于理解。使用方式上,可以显式对对象加锁synchronized(obj){},也可以隐式对当前对象加锁,就是所谓的同步方法或者synchronized(this){}代码块。这里多说一句,因为synchronized是依附对象的加锁策略,所以在普通方法上加synchronized修饰,加锁范围是当前类的实例,对静态方法上加synchronized修饰,加锁范围为Class类实例,两者属于不同对象,所以不存在竞争问题。
<span style="font-family:FangSong_GB2312;"><span style="font-size:18px;">public class t{ public static void main(String[] args){ final test te=new test(); new Thread(){ public void run(){ synchronized(test.class){ System.out.println("subthread1:"+Thread.currentThread().getId()+"start"); try{ Thread.sleep(3000); }catch(Exception e){ e.printStackTrace(); } System.out.println("subthread1:"+Thread.currentThread().getId()+"end"); } } }.start(); try{ Thread.sleep(100); }catch(Exception e){ e.printStackTrace(); } te.plain_meth(); te.staic_meth(); } } class test{ public synchronized static void staic_meth(){ System.out.println("main staic_meth:"+Thread.currentThread().getId()); } public synchronized void plain_meth(){ System.out.println("main plain_meth:"+Thread.currentThread().getId()); } }</span></span>执行结果
<span style="font-family:FangSong_GB2312;"><span style="font-size:18px;">subthread1:8start main plain_meth:1 subthread1:8end main staic_meth:1</span></span>
调用对象的wait方法,使当前线程进入阻塞状态,直到被notify、notifyAll唤醒。notify、notifyAll方法属于大范围无差别唤醒策略,当前进程空间内的所有调用wait进入阻塞状态的线程都可能响应,没有针对性。
生产者消费者示例
<span style="font-family:FangSong_GB2312;"><span style="font-size:18px;">public class t{ private static final int CAPACITY = 3; public static void main(String[] args){ Buff buf=new Buff(CAPACITY); for(int i=0;i<10;i++){ new Producer("Producer "+i,buf).start(); new Consumer("Consumer "+i,buf).start(); } } } class Buff{ private final Object[] obj; private int index=0; public Buff(int CAPACITY){ obj=new Object[CAPACITY]; } public void put(Object o){ obj[index++]=o; } public Object take(){ return obj[--index]; } public boolean isEmpty(){ return index==0; } public boolean isFull(){ return obj.length==index; } public int getContent(){ return index; } } class Producer extends Thread{ private Buff buf; public Producer(String name,Buff buf){ super(name); this.buf=buf; } public void run(){ produce(); } private void produce(){ synchronized(buf){ while(buf.isFull()){ try{ buf.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } buf.put(new Object()); System.out.println(Thread.currentThread().getName()+" put a product"); System.out.println("concurrent buf content: "+buf.getContent()); buf.notify(); } } } class Consumer extends Thread{ private Buff buf; public Consumer(String name,Buff buf){ super(name); this.buf=buf; } public void run(){ consume(); } private void consume(){ synchronized(buf){ while(buf.isEmpty()){ try{ buf.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } buf.take(); System.out.println(Thread.currentThread().getName()+" take a product"); System.out.println("concurrent buf content: "+buf.getContent()); buf.notify(); } } } </span></span>
这里说一下,生产者线程判断buf不满使用的检查条件是while(buf.isFull()){},这里使用while循环而不是if判断。因为当某一个消费者线程con调用了notify后,会有某个因为wait而阻塞的生产者线程pro被唤醒,但是此时con仍然占据锁,需要等con代码块执行完毕,释放锁后,pro获得锁开始执行,如果con脑袋秀逗了,notify后,加了一句buf.put(new
Object()),则pro在if语句的wait醒来后,直接向下执行,可能抛出越界异常。
总结
Synchronized、wait、notify、notifyAll可以实现一定程度的线程协调作用,但是在灵活性方面做的不好,引入Lock、Condition可以在一方面弥补这些缺陷,当然API层次的locks包也有不足。
相关文章推荐
- C#实现子窗体与父窗体通信方法实例总结
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- 简单对比C#程序中的单线程与多线程设计
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- java和c#使用hessian通信的方法
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- 探究在C++程序并发时保护共享数据的问题
- win32下进程间通信(共享内存)实例分析
- VB读取线程、句柄及写入内存的API代码实例
- 在ASP.NET 2.0中操作数据之四十八:对SqlDataSource控件使用开放式并发
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- WinForm实现跨进程通信的方法
- C#多线程处理多个队列数据的方法
- C#中使用UDP通信实例