Java多线程之通过管道线程间通信(字节流、字符流),类ThreadLocal与类InheritableThreadLocal的使用
来源:互联网 发布:java数组按大小排序 编辑:程序博客网 时间:2024/05/21 13:48
一、通过管道线程间通信(字节流、字符流)
在Java语言中提供了各种各样的输人/输出流Stream,使我们能够很方便地对数据进行操作,其中管道流(pipeStream)是一种特殊的流,用于在不同线程间直接传送数据。一个线程发送数据到输出管道,另一个线程从输人管道中读数据。通过使用管道,实现不同线程间的通信,而无须借助于类似临时文件之类的东西。
在Java的JDK中提供了4个类来使线程间可以进行通信:
1)PipedInputStream和PipedOutputStream
2)PipedReader和PipedWriter
1、通过管道进行线程间通信:字节流/字符流
public class WriteData { public void writeMethod(PipedOutputStream out) { //字符流这里换成PipeWriter try { System.out.println("write :"); for (int i=0; i<10; i++) { String outData = "" + (i+1); out.write(outData.getBytes()); //字符流这里换成out.write(outData) System.out.print(outData); } System.out.println(); out.close(); } catch (IOException e) { e.printStackTrace(); } }}public class ReadData { public void readMethod(PipedInputStream input) { //字符流这里换成PipedReader try { System.out.println("read: "); byte[] byteArray = new byte[20]; //字符流这里换成char int readLength = input.read(byteArray); while (readLength != -1) { String newData = new String(byteArray, 0, readLength); System.out.println(newData); readLength = input.read(byteArray); } System.out.println(); input.close(); } catch (IOException e) { e.printStackTrace(); } }}
两个自定义线程
public class ThreadWrite extends Thread { private WriteData write; private PipedOutputStream out; //字符流这里换成PipedWriter public ThreadWrite(WriteData write, PipedOutputStream out) { //字符流这里换成PipedWriter this.write = write; this.out = out; } public void run() { write.writeMethod(out); }}public class ThreadRead extends Thread { private ReadData read; private PipedInputStream input; //字符流这里换成PipedRead public ThreadRead(ReadData read, PipedInputStream input) { //字符流这里换成PipedRead this.read = read; this.input = input; } public void run() { read.readMethod(input); }}
public class Run { public static void main(String[] args) throws InterruptedException, IOException { WriteData writeData = new WriteData(); ReadData readData = new ReadData(); PipedInputStream inputStream = new PipedInputStream(); //字符流用PipedReader PipedOutputStream outputStream = new PipedOutputStream(); //字符流用PipedWriter inputStream.connect(outputStream); //这两个只能用一个 //outputStream.connect(inputStream); ThreadRead threadRead = new ThreadRead(readData,inputStream); threadRead.start(); Thread.sleep(2000); ThreadWrite threadWrite = new ThreadWrite(writeData,outputStream); threadWrite.start(); }}
read:
write :
12345678910
12345678910
使用代码inputStream.connect(outputStream)或outputStream.connect(inputStream)的作用使两个 Stream之间产生通信链接,这样才可以进行输出输入。
二、类ThreadLocal与类InheritableThreadLocal的使用
2.1.类ThreadLocal的使用
变量值的共享可以使用public static 变量的形式,所有的线程都使用同一个public static变量。如果想实现每一个线程都有自己的共享变量该如何解决呢?JDK中提供的类ThreadLocal正是为了解决这样的问题。
类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。
1、方法get()与null
public class Run { public static ThreadLocal threadLocal = new ThreadLocal(); public static void main(String[] args) throws InterruptedException { if (threadLocal.get() == null) { System.out.println("从未放过值。"); threadLocal.set("我的值"); } System.out.println(threadLocal.get()); }}
从未放过值。
我的值
从运行结果来看,第一次调用threadLocal对象的get()方法时返回的值是null,通过调用set()方法赋值后顺利取出值并打印到控制台上。
类Threadlocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程中的值是可以放人Threadlocal类中进行保存的。
2、验证线程变量的隔离性
多个线程用一个ThreadLocal类
public class Tools { public static ThreadLocal t1 = new ThreadLocal();}// 两个自定义的线程public class MyThread1 extends Thread { public void run() { try { for (char i='a'; i<'z'; i++) { Tools.t1.set("Thread1-" + i); System.out.println("Thread1 get value=" + Tools.t1.get()); Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } }}public class MyThread2 extends Thread{ public void run() { try { for (int i=0; i<30; i++) { Tools.t1.set("Thread2—" + (i+1)); System.out.println("Thread2 get value=" + Tools.t1.get()); Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } }}public class Run { public static void main(String[] args) throws InterruptedException { MyThread1 a = new MyThread1(); MyThread2 b = new MyThread2(); a.start(); b.start(); for (int i=0; i<33; i++) { Tools.t1.set("Main" + (i+1)); System.out.println("Main get value=" + Tools.t1.get()); Thread.sleep(200); } }}
Main get value=Main1
Thread2 get value=Thread2—1
Thread1 get value=Thread1-a
Thread1 get value=Thread1-b
Thread2 get value=Thread2—2
Main get value=Main2
Thread1 get value=Thread1-c
Main get value=Main3
Thread2 get value=Thread2—3
……
虽然3个线程都向t1对象中set()数据值,但每个线程还是能取出自己的数据。
3、解决get()返回null的问题
重写ThreadLocal方法,得到初始值,这样第一次get不再为null
public class ThreadLocalExt extends ThreadLocal { @Override protected Object initialValue() { return "重写ThreadLocal方法,得到初始值,让第一次get不再为null"; }}public class Run { public static ThreadLocalExt t1 = new ThreadLocalExt(); public static void main(String[] args) throws InterruptedException { if (t1.get() == null) { System.out.println("从未放过值"); t1.set("我的值"); } System.out.println(t1.get()); }}
2.2、类InheritableThreadLocal的使用
使用InheritableThreadLocal类可以让子线程从父线程中取得值。
1、值继承
public class InheritableThreadLocal extends ThreadLocal
public class InheritableThreadLocalExt extends InheritableThreadLocal { @Override protected Object initialValue() { return new Date().getTime(); }}public class Tools { public static InheritableThreadLocalExt t1 = new InheritableThreadLocalExt();}public class MyThread1 extends Thread { public void run() { try { for (int i=0; i<5; i++) { System.out.println("Thread1 get value=" + Tools.t1.get()); Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } }}public class Run { public static void main(String[] args) throws InterruptedException { for (int i=0; i<5; i++) { System.out.println(" 在Main线程中取值=" + Tools.t1.get()); Thread.sleep(100); } Thread.sleep(3000); MyThread1 a = new MyThread1(); a.start(); }}
在Main线程中取值=1462588336441
在Main线程中取值=1462588336441
在Main线程中取值=1462588336441
在Main线程中取值=1462588336441
在Main线程中取值=1462588336441
Thread1 get value=1462588336441
Thread1 get value=1462588336441
Thread1 get value=1462588336441
Thread1 get value=1462588336441
Thread1 get value=1462588336441
2、值继承再修改
再继承的同时还可以对值进行进一步的处理(但是在使用InheritableThreadLocal类需要注意一点的是,如果子线程在取得值的同时,主线程将InheritableThreadLocal中的值更改,那么 子线程取到的值还是旧值)。修改如下
public class InheritableThreadLocalExt extends InheritableThreadLocal { @Override protected Object initialValue() { return new Date().getTime(); } @Override protected Object childValue(Object parentValue) { return parentValue + " 重写后在子线程加的!"; }}
在Main线程中取值=1462588868404
在Main线程中取值=1462588868404
在Main线程中取值=1462588868404
在Main线程中取值=1462588868404
在Main线程中取值=1462588868404
Thread1 get value=1462588868404 重写后在子线程加的!
Thread1 get value=1462588868404 重写后在子线程加的!
Thread1 get value=1462588868404 重写后在子线程加的!
Thread1 get value=1462588868404 重写后在子线程加的!
Thread1 get value=1462588868404 重写后在子线程加的!
- Java多线程之通过管道线程间通信(字节流、字符流),类ThreadLocal与类InheritableThreadLocal的使用
- Java多线程编程3--线程间通信--类ThreadLocal与类InheritableThreadLocal的使用
- Java多线程编程3--通过管道线程间通信(字节流、字符流)
- Java多线程之ThreadLocal和InheritableThreadLocal的使用
- JAVA多线程-线程间通信(五)-类ThreadLocal的使用
- ThreadLocal与InheritableThreadLocal的使用
- ThreadLocal与InheritableThreadLocal的使用
- 3.6线程间的通信:字节流与字符流
- 多线程 通过管道进行线程间通信
- 类InheritableThreadLocal的使用
- Java多线程之----InheritableThreadLocal
- java 多线程通信之管道流
- threadlocal与inheritableThreadLocal的区别
- JAVA多线程-线程间通信(三)-通过管道进行线程间通信
- java线程之InheritableThreadLocal
- java线程之InheritableThreadLocal
- ThreadLocal和InheritableThreadLocal的使用
- ThreadLocal和InheritableThreadLocal的使用
- Container With Most Water
- 如何修改MFC主窗口的大小
- 实现ViewPager懒加载的三种方法
- Java静态代理和动态代理的简单代码实现。
- CORS跨域资源共享你该知道的事儿
- Java多线程之通过管道线程间通信(字节流、字符流),类ThreadLocal与类InheritableThreadLocal的使用
- 内存溢出和内存泄漏
- Hibernate一
- Android中ViewPager+Fragment取消(禁止)预加载延迟加载(懒加载)问题解决方案
- easyui中在datagrid中右键出现菜单
- 关于Android studio 无法启动
- es6(2)
- poj Ugly Numbers
- 武功秘籍