线程_IO串讲

来源:互联网 发布:简单的c语言代码 编辑:程序博客网 时间:2024/04/29 01:56

07-03-01线程_IO串讲

 

进程是一套顺序执行的指令。

同时开辟并行执行序列即多线程          run() 结束,线程就结束

JVM就是一个进程,在JVM中分出线程

进程数据空间独立;线程数据空间共享, 线程间通信更容易

分配的方式不如线程好,能充分使用CPU的资源。 共享数据就要加锁、解锁,会降低效率。

 

OS 时分共享操作系统 实时操作系统

时分共享操作系统    时间片    调度系统把每个时间片分给多个进程   性能调优是根据时间片划分, 时间片会影响整个操作系统。

 

为了让某些工作并行,在进程主线程中开辟多个线程,这就是线程的机制。

 

 

我们关心的是被线程共享的数据,主要看synchronized加在何处。往往不加在线程里面,而是在共享的对象上。

 

只有运行状态的线程才有机会执行代码!

只有等到所有线程终止,进程才结束!

当一个对象分配给某线程锁标记时,其它线程不能访问同步方法,但能访问非同步方法!

 

起线程的两种方式:1、继承Thread,覆盖run()方法,用start()启动

                  2、实现Runnable接口,用来构造线程对象。(线程对象不是线程,但代表一个线程)

例子 ProducerConsumer.java

每一个对象都有一个互斥锁标记(monitor),这个锁标记是准备分配给线程的,且只能分配给一个线程

用法一:

synchronized(o){

     原子操作代码块

}

哪个线程能拿到o的锁标记,哪个线程才能进入这个同步代码块,用完后释放锁标记

未加同步可能造成数据不一致和数据不完整的缺陷。

 

用法二:

public synchronized void method(){ …}      

等价于:

Public void method(){

           Synchronized(this){...}

}    

在整个方法中,对this加锁。

 

l         构造方法   不能同步,因为还没有当前对象

l         抽象方法   也不能同步,因为子类覆盖方法后可以是非同步方法,父类就有多余的话。

 

每一个对象都有一个锁池,装的是等待该对象锁标记的线程。

 

一个线程可以同时拥有多个对象的锁标记

     synchronized(o1){                //同步代码块是可以嵌套的

           synchronized(o2){

           }

     }

 

当一个线程阻塞在A对象的锁池里的时候,不会释放其所拥有的其他对象的锁标记

 

每个线程不释放自己拥有的资源,却申请别的线程的资源,就可能造成死锁问题

 

线程t1:   o.wait()  

前提:  必须在对o加锁的同步代码块里

1.  t1会释放其所拥有的所有锁标记

2.  t1会进入o的等待队列

 

线程t2: o.notify() / o.notifyAll()

前提:必须在对o加锁的同步代码块里

t2会从o的等待队列中释放一个线程/所有线程

 

推荐:尽量用notifyAll取代notify, 因为由OS决定只释放哪个线程

 

 

wait() sleep()的联系和区别:

1. wait()是从Object继承下来的方法,而sleep()Thread中的静态方法

2. wait() sleep()都要阻塞运行,释放CPU资源

3. wait()要释放锁; sleep()不释放锁

wait()方法被调用时会解除锁定,但是我们能使用它的地方只是在一个同步方法或代码块内。

 

新思路:必要时可利用Object中的 锁标记锁池等待队列 用其wait() / notify() 方法,

       自己制造临界资源来进行线程间通讯。

      (参考字母数字交叉打印的例子TestNumberCharPrint.java

       其中注意o.notifyAll() o.wait() 的调用顺序,还要注意边界问题,体现在最后要来一个判断if(c!=’Z’)  o.wait(); 进而让程序正常结束。

 

 

I/O

一、流的分类

  1 数据传输方向划分:输入流和输出流

I  输入流      JVM ——>数据源      InputXXX

O  输出流     JVM <—— 数据源      OutputXXX

 

2 数据单位划分:字节流和字符流

       字节流   一次传输一个字节

       字符流   一次传输一个字符

字节流类:

抽象父类: InputStream     字节输入流 xxxInputStream

实现类:

                     BufferedInputStream 缓冲流——过滤流   

                     ByteArrayInputStream 字节数组流——节点流

                     DataInputStream    处理Java标准数据流——过滤流

                     FileInputStream 处理文件IO流——节点流

            FilterInputStream 实现过滤流——字节过滤流父类

                     PipedInputStream 管道流,在两个线程交换数据

                     PrintStream  包含print() println()

                     RandomAccessFile 只支持随机访问文件,用于定位的seek()方法。 了解即可

                     SequenceInputStream 在合并两个文件是较好用(顺序流)

     字符流:

可以解决字符编码问题

ReaderWriter (字符流类,所有字符流的父类型)

3)按流的功能划分:

节点流 / 过滤流(使用装饰模式

        节点流用来传输数据。

     过滤流用来封装节点流或者其他过滤流,从而给节点流或其他的过滤流增加功能。

            首先要通过构造得到InputStream OutputStream 对象

            关闭流时只需关最外层的流。

            注意使用out.flush()来清空缓冲区。 out.close()默认调用flush

I/O本身是抽象的,当 目的确定了I/O就不抽象了。

 

u       构造方法的记忆方法:

(1)、代表的事物,构造方法就加

例如  FileInputStream   File代表源的事物,构造方法就加源

      FeInputStreamil(File file)

(2)、代表功能,构造方法就放InputStream OutputStream

例如  ObjectInputStream  Object代表功能,构造方法就放InputStream

      DataInputStream   Data分为intbytechar8种简单类型外加String

构造方法放InputStream

      PushbackInputStream  Pushback代表具有缓冲的功能,所以构造方法放InputStream

InputStream, OutputStream为抽象的,子类型不抽象

建议主要记Read / Write 方法即可,其它的掌握规律

比如看到Data就要想到会装不同类型数据: intbytechar …

 

 

InputStream

所有字节输入流的父类,如:FileInputStream,ObjectInputStream,PipedInputStrean

三个基本的read()方法

   A.  int read() 从流里读出的一个字节或者返回-1;

   B.  int read(byte[]):将数据读入到字节数组中,并返回所读的字节数;

C.  int read(byte[], int p, int len)int参数p表示哪个位置,len表示希望的长度。

 

FileInputStream

DataInputStream

PipedInputStream类(一般了解)

BuferOutputStream 给流增加一个缓冲的功能,以空间换取时间。   TestBufferedStream.java

 

JVM

Data Source

缓冲区

 

 


        JVM内部开辟一块缓冲区,提高了读写的效率

 

根据数据类型选择输入/输出流:

bytebyte[]       InputStream / OutputStream

intbytechar    DataInputStream / DataOutStream

charString       Reader / Writer

Object            ObjectInputStream / ObjectOutputStream

若考虑性能会在前试着加Buffered,  上加;   则在的基础上加。

 

FileOutputStream fo=new FileOutputStream(“a.txt”);

   BufferedOutputStream out=new BufferedOutputStream(fo);

   DataOutputStream dout=new DataOutStream(out);

 

字符流:

   可以解决字符编码问题       

 每个国家制定编码方式,编码方式、解码方式不同——>乱码问题

ASCII             一个字符-----1B     任何一种编码均兼容    A<-->65

ISO8855-1 (西欧)    一个字符-----1B

GB-2312 / GBK     一个字符-----2B

Unicode            一个字符-----2B    会增加网络负担    Java中的charUnicode

UTF-8            变长字节(变长的Unicode方式)

                  英文-----1B

                  中文-----3B

 

这里的重点: 字节流——>字符流

 InputStreamReader

 OutputStreamWriter

 

   FileInputSream fi=new FileInputStream(“2.txt”);

  InputStreamReader ir=new InputStreamReader(fi,”Big5”);   //在桥转换时指定编码方式

   BufferedReader in=new BufferedReader(ir);

 

   String s;

   While((s=in.readLine())!=null){     //readLine()阻塞方法,到换行符为止

        System.out.println(s);

   }

   in.close();

Java EE中用得较多的还是ReaderWriter