Synchronized关键字与线程通信
2016-05-15 13:21
531 查看
一.等待/通知机制
1.通过wait/notify实现等待/通知机制
wait():可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒
notify():可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程,且随机
notifyAll():可以使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态
在多线程程序中,单个线程可能会需要满足某些逻辑条件才能继续运行。当线程所要求的条件不满足时,线程进入等待状态,等待由于其他线程的运行而使条件得到满足;其他线程则负责在合适的时机发出通知来唤醒处于等待状态的线程。对于这种场景,可以使用while循环和volatile变量来处理。但是这种做法的本质是让线程处于忙等待的状态,并通过轮询的方式来判断条件是否满足。处于忙等待的线程仍然占用CPU时间,对性能造成影响。更好的做法是使用Object类提供的wait、notify和notifyAll
例1:使用wait/notify实现等待/通知机制
运行结果:
begin wait() ThreadName=Thread-0
begin wait() ThreadName=Thread-1
end wait() ThreadName=Thread-0
例2:使用wait/notifyAll实现等待/通知机制
将例1中的notify换成notifyAll
运行结果:
begin wait() ThreadName=Thread-0
begin wait() ThreadName=Thread-1
end wait() ThreadName=Thread-1
end wait() ThreadName=Thread-0
二.通过管道进行线程间通信
在java语言中提供了一种特殊的流,管道流,用于在不同线程间直接传送数据,一个线程发送数据到输出管道,另一个线程从输入管道中读取数据
在javaJDK中提供了4个类来使线程间可以通信:
1)字节流:PipedInputStream和PipedOutputStream
2)字符流:PipedReader和PipedWriter
1.字节流
例1:使用管道字节流实现线程通信
运行结果:
write:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
Read:
12345678910111213141
Read:
51617181920212223242
Read:
52627282930313233343
Read:
53637383940414243444
Read:
54647484950
2.字符流
只需要将PipedInputStream和PipedOutputSteam对象变成PipedReader和PIpedWriter对象即可
1.通过wait/notify实现等待/通知机制
wait():可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒
notify():可以随机唤醒等待队列中等待同一共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程,且随机
notifyAll():可以使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态
在多线程程序中,单个线程可能会需要满足某些逻辑条件才能继续运行。当线程所要求的条件不满足时,线程进入等待状态,等待由于其他线程的运行而使条件得到满足;其他线程则负责在合适的时机发出通知来唤醒处于等待状态的线程。对于这种场景,可以使用while循环和volatile变量来处理。但是这种做法的本质是让线程处于忙等待的状态,并通过轮询的方式来判断条件是否满足。处于忙等待的线程仍然占用CPU时间,对性能造成影响。更好的做法是使用Object类提供的wait、notify和notifyAll
例1:使用wait/notify实现等待/通知机制
public class WaitAndNotify { static String obj="obj"; public static void main(String[] args) { // TODO Auto-generated method stub WaitAndNotify waitAndNotify=new WaitAndNotify(); Runnable thread1=new Runnable() { @Override public void run() { // TODO Auto-generated method stub synchronized(obj){ System.out.println("begin wait() ThreadName="+Thread.currentThread().getName()); try { obj.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("end wait() ThreadName="+Thread.currentThread().getName()); } } }; Runnable thread2=new Runnable() { @Override public void run() { // TODO Auto-generated method stub synchronized (obj){ System.out.println("begin wait() ThreadName="+Thread.currentThread().getName()); try { obj.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("end wait() ThreadName="+Thread.currentThread().getName()); } } }; (new Thread(thread1)).start(); (new Thread(thread2)).start(); synchronized(obj){ obj.notify(); } } }
运行结果:
begin wait() ThreadName=Thread-0
begin wait() ThreadName=Thread-1
end wait() ThreadName=Thread-0
例2:使用wait/notifyAll实现等待/通知机制
将例1中的notify换成notifyAll
synchronized(obj){ obj.notifyAll(); }
运行结果:
begin wait() ThreadName=Thread-0
begin wait() ThreadName=Thread-1
end wait() ThreadName=Thread-1
end wait() ThreadName=Thread-0
二.通过管道进行线程间通信
在java语言中提供了一种特殊的流,管道流,用于在不同线程间直接传送数据,一个线程发送数据到输出管道,另一个线程从输入管道中读取数据
在javaJDK中提供了4个类来使线程间可以通信:
1)字节流:PipedInputStream和PipedOutputStream
2)字符流:PipedReader和PipedWriter
1.字节流
例1:使用管道字节流实现线程通信
//写 import java.io.IOException; import java.io.PipedOutputStream; public class WriteData extends Thread { PipedOutputStream out; public WriteData(PipedOutputStream out){ this.out=out; } public void writeMethod(PipedOutputStream out) throws IOException{ System.out.println("write:"); for(int i=0;i<50;i++){ String outData=""+(i+1); out.write(outData.getBytes()); System.out.print(outData); } out.close(); System.out.println(); } @Override public void run() { // TODO Auto-generated method stub super.run(); try { writeMethod(out); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //读 import java.io.IOException; import java.io.PipedInputStream; public class ReadData extends Thread { PipedInputStream in; public ReadData(PipedInputStream in){ this.in=in; } public void readMethod(PipedInputStream in) throws IOException{ byte[] b=new byte[20]; int readLength=in.read(b); while(readLength!=-1){ String newData=new String(b,0,readLength); System.out.println("Read:"); System.out.println(newData); readLength=in.read(b); } in.close(); } @Override public void run() { // TODO Auto-generated method stub super.run(); try { this.readMethod(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //测试程序 import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Main { public static void main(String[] args) throws IOException { // TODO Auto-generated method stub PipedOutputStream out=new PipedOutputStream(); PipedInputStream in=new PipedInputStream(); out.connect(in); WriteData write=new WriteData(out); ReadData read=new ReadData(in); write.start(); read.start(); } }
运行结果:
write:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
Read:
12345678910111213141
Read:
51617181920212223242
Read:
52627282930313233343
Read:
53637383940414243444
Read:
54647484950
2.字符流
只需要将PipedInputStream和PipedOutputSteam对象变成PipedReader和PIpedWriter对象即可
相关文章推荐
- C#实现子窗体与父窗体通信方法实例总结
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- 简单对比C#程序中的单线程与多线程设计
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- java和c#使用hessian通信的方法
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- win32下进程间通信(共享内存)实例分析
- VB读取线程、句柄及写入内存的API代码实例
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- WinForm实现跨进程通信的方法
- C#多线程处理多个队列数据的方法
- C#中使用UDP通信实例
- ASP.NET UserControl 通信的具体实现
- C#实现线程安全的简易日志记录方法