zoukankan      html  css  js  c++  java
  • java面试第十二天

    多线程:

             多线程的同步:    

                      多线程并发访问同一个对象(临界资源),如果不对线程进行同步控制,破坏了原子操作(不可再分的操作),则会造成临界资源(两个线程同时访问的资源)的数据不一致。  

                      每一个对象都有一个互斥的锁标记和一个锁池。当线程拥有这个对象的锁标记时才能访问这个资源,没有锁标记便进入锁池,保证在同步代码块中只有一个线程,解决了多线程同步控制的问题。

                     

                      关键字:synchronized   //线程在同步代码中必须采用串行访问

                               synchronized修饰代码块:对括号内的对象object加锁,只有拿到对象锁标记的线程才能进入该代码块。

                                    public void push(char c){

                                                synchronized(object){     //object只要是对象就可以,但必须保证是同一对象

                                                         ……

                                                         同步代码

                                                         ……

                                                }

                                    }

                                   

                               synchronized修饰方法:在整个方法范围内对当前对象的加锁,只有拿到对象锁标记的线程才能执行该方法。尽可能的少用

                                    public synchronized void push(char c) {

                                                 ……

                                                 同步代码

                                                 ……  

                                        }

                                         

                      一个线程可以同时拥有多个对象的锁标记,锁标记如果过多,就会出现线程等待其他线程释放锁标记,而又都不释放自己的锁标记供其他线程运行的状况,造成死锁。                                   

                      静态方法可以是同步方法:但是它所锁的并不是当前对象,是类对象。

                      抽象方法不能是synchronized同步的方法。

                      构造方法不能是synchronized同步的方法。

                              

                      线程因为未拿到锁标记而发生阻塞进入锁池(lock pool)。每个对象都有自己的一个锁池的空间,用于放置等待运行的线程。由系统决定哪个线程拿到锁标记并运行

                     

                      利用Collections类中的synchronizedXxxx(Xxxx ss)方法可以得到相应集合的线程安全的集合

                     

                      注意:

                               在同步语句块中不能直接操作对象锁正在使用的对象。

                               对象与锁一一对应。

                               同步依赖对象锁,锁对象相同,同步语句串行,锁对象不同,同步语句并行。

                               顺序锁,不要回调,反向打开。

                               能不用同步就不用同步,有数据共享冲突时才使用同步。

                     

             等待通知机制:

                      线程间通信使用的空间称之为对象的等待对列(wait pool),该队列也是属于对象的空间的。

                     

                      使用Object类中wait()的方法,在运行状态中,线程调用wait(),此时表示线程将释放自己所有的锁标记和CPU的占用,同时进入这个对象的等待池。等待池的状态也是阻塞状态,只不过线程释放自己的锁标记。只有在对该对象加锁的同步代码块里,才能掉用该对象的wait(),表示线程将会释放所有锁标记,进入等待队列,线程将进入等待队列状态。

                     

                      一个线程进入了一个对对象加锁的同步代码块,并对该对象调用了wait()方法,释放自己拥有的所有锁标记,进入该对象等待队列,另一个线程获得了该对象的锁标记,进入代码块对该对象调用了notify()方法,就会从等待队列里释放出一线程,释放出的这个线程要继续运行就还要进入那个同步代码块,因为得不到要访问代码块对象的锁标记,而进入该对象的锁池,等待锁标记释放。

                     

                      什么情况下释放锁:

                               同类代码执行完毕。

                               异常未处理,错误退出。

                               调用wait()。

                     

                      相关方法:

                               1) wait():交出锁和CPU的占用;

                               2) notify():将从对象的等待池中移走一个任意的线程,并放到锁池中,那里的对象一直在等待,直到可以获得对象的锁标记。

                               3) notifyAll(): 将从等待池中移走所有等待那个对象的线程并放到锁池中,只有锁池中的线程能获取对象的锁标记,锁标记允许线程从上次因调用wait()而中断的地方开始继续运行

                              

                      注意:

                               用notifyAll()取代notify(),因为在调用notify()方法时,是由系统决定释放出哪个线程。

                               只能对加锁的资源进行wait()和notify()。

                               判断是否进行等待wait()时,用while代替if来进行判断。

                              

    I/O流

             字节输入流:InputStream类为所有字节输入流的父类

                      三个基本的read()方法:

                                 int read()

                                          从流里读出的一个字节。不推荐使用

                                 int read(byte[] b)

                                          将数据读入到字节数组中,并返回所读的字节数

                                 int read(byte[] b, int off, int len)

                                          off  从哪里开始读。

                                          len  读取多少。

                                          将输入流中最多 len 个数据字节读入字节数组。

                      其它方法:

                                 void close()

                                          关闭此输入流并释放与该流关联的所有系统资源。

                                 int available()

                                          返回不受阻塞地从此输入流读取的字节数。

                                 long skip(long n)

                                          跳过和放弃此输入流中的n个数据字节,该方法有可能失效。

                                 boolean markSupported()

                                          测试此输入流是否支持 mark 和 reset 方法。

                                 void mark(int n)

                                          在此输入流中标记当前的位置

                                 void reset()

                                          将此流重新定位到对此输入流最后调用 mark 方法时的位置。

             字节输出流:OutputStream类是所有字节输入流的父类

                      三个基本的write()方法:

                               void write(int n)

                                        将指定的字节写入此输出流。

                               void write(byte[] b)

                                        将 b.length 个字节从指定的字节数组写入此输出流。

                               void write(byte[] b, int off, int len)

                                        将指定字节数组中从偏移量off开始的len个字节写入此输出流。

                      其它方法:

                               void close()

                                          关闭此输出流并释放与此流有关的所有系统资源。

                               void flush()

                                          刷新此输出流并强制写出所有缓冲的输出字节。

                                         

             文件输入输出流:FileInputStream和FileOutputStream

                      要构造一个FileInputStream,所关联的文件必须存在而且是可读的。

                               如:

                                        FileInputStream fis = new FileInputStream("myfile.dat");

                      要构造一个FileOutputStream,而输出文件已经存在,则它将被覆盖。                       

                               如:                          

                                    FIleOutputStream fos = new FileOutputStream("results.dat");

                           要想以追加的方式写,则需要一个额外的参数,如:

                                        FileOutputStream outfile = new FileOutputStream("results.dat" ,true);        //参数为true时输出为追加,为false时为覆盖。

  • 相关阅读:
    Vue.js组件理解
    Vue.js 基础知识
    JS-WEB-API 整理
    JS面向对象基础
    JS基础知识系统整理(不断更新)
    图解关于pageX,pageY,screenX,screenY,clientX,clientY的区别
    妙味JS学习记录(二)
    Ajax全接触笔记
    妙味JS学习记录(一)
    c#设计模式系列:状态模式(State pattern)
  • 原文地址:https://www.cnblogs.com/hoobey/p/5187656.html
Copyright © 2011-2022 走看看