实习第二周周报

这周主要学习了集合,IO,多线程

一、集合

  1.集合主要继承图(核心卷1)

 

 

 

  2.ArrayList

    arrayList是非同步的基于动态数组实现,在arrayList的类中描述到在集合在进行size、isEmpty、get、set、iterator、listIterator操作时,会发生fail-fast机制,因为在这些操作会checkForComodification()检查modCount和exceptmodCount的预期值是否相等,但在多线程时会产生类似读写不一致的现象的事情,从而发生fail-fast的事情。(并发下用JUC下的CopyOnWrite可以避免这种错误)

    在扩容时,每次会扩大到原来的1.5倍,并用Arrays.copyOf()将旧数组复制到新数组,耗费很大,所以如果在已知需要多少容量时在创建时指定容量大小,减少扩容的次数。

  3.LinkedList

    linkedList是基于双向链表实现,所以他在删除和插入元素时会更快,但查询元素时就会通过遍历的方式,同样也会发生fail-fast

  4.Vector和CopyOnWriteArrayList

    他们都是同步方法,vector是早期的方法通过synchronize进行同步操作,verctor每次扩容时是原来的2倍,

    verctor并不被推崇,如果想要同步方法,可以用如下方法代替

 List<String> list = new ArrayList<>();
 List<String> synList = Collections.synchronizedList(list); 
也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。 

    CopyOnWriteArrayList是JUC下的类,他进行了读写分离:写操作在一个复制的数组上进行,读操作还在原来的数组上进行。写操作需要加锁,并在写完后需要将原始数组指向新数组。所以CopyOnWriteArrayList适合读多写少的场景,但是他缺点也很明显:①。读写两个数组,内存占用多 ②。读写分离,导致每次读操作不一定是最新的。所以他不适合内存敏感和实时性要求很高的场景

  5.HashMap

    hashmap底层采用数组加链表的方式进行存储,链表采用的头插法,在进行hash时将key的hashcode与自己>>>16进行亦或操作,HashMap的初始大小和扩容都是以2的次方来进行的,在确定的桶的位置时通过(legth-1)&hash,的方式来减少hash冲突,在进行扩容时同样通过将旧数组重新放入到新数组的操作,同样很费事

二、并发    

  1.多线程与多进程的区别:

    ①、每个进程有自己的一整套变量,进程间共享数据 ②、共享变量使得线程间通信比进程间容易 ③、线程更加轻量级 ④、线程共享使得不安全

  2.线程状态

    • New(新创建)
    • Runbale(可运行)
    • Blocked(被阻塞)
    • Waiting(等待)
    • Time Waiting(计时等待)
    • Terminated(被终止)

     

   

  • New(新创建)
  • Runbale(可运行)
  • Blocked(被阻塞)
  • Waiting(等待)
  • Time Waiting(计时等待)
  • Terminated(被终止)

   2.1 New状态

  当用new操作创建一个线程后,该线程还没有运行,此时状态为New,程序还没有运行线程中的代码,在运行之前还有一些基础工作要做

  2.2 Runable

  一旦调用start方法,线程处于Runable状态,一个可运行的线程可能正在运行也可能没有运行,这取决于操作系统给线程分配的时间

 2.3 Blocked和Waiting

  当线程处于Blocked和Waiting时,他暂时不活动。他不运行任何代码且消耗最少的资源,直到线程调度器重新激活它,细节取决于他是怎样到达非活动状态的

   当一个线程试图获取一个内部的对象锁(而不是JUC库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态,当其他线程释放该锁,并且线程调度器允许本线程持有他的时候,该线程进入非阻塞状态,

  当线程等待另一个线程通知调度器一个条件时,他自己进入等待状态。在调用Object.wait()或Thred.join(),或者是等待JUC库中Lock或Condition时,就会出现这种情况

  有几个方法(thread.sleep,object.wait thread.join, lock.tryLock ,Condition.await)有一个计时参数,调用他们导致线程进入计时等待状态。这一状态将一直保持到超时期满或者接收到适当的通知,

  3.线程优先级

      每一个线程有一个优先级,默认一个线程继承他父线程的优先级。可以用setPriority提高或降低一个线程的优先级,线程优先级是高度依赖系统的,所以不要将程序构建为功能依赖于优先级的程序。

  4.synchronize

    synchronize分为对象锁和类锁。当synchronize作用在非静态方法和代码块时,此时是对象锁,他会对同一个对象进行锁,在此情况下这个类中的synchronize方法都将进行同步操作,而非synchronize方法可以并行访问;

    当synchronize作用在静态方法和synchronize(类名.class){}进行类锁,此时此类的所有对象都会进行同步。

  5.中断线程   

    在java的早期版本中,还有一个stop方法,其他线程可以调用它终止线程,但是,这个方法已经被弃用了,因为他的强制停止是非常错误的,在进行操作时会发生各种结果。

    现在没有可以强制停止线程的方法,但使用interrupt可以用来请求中断线程,他并不会立即停止线程,并且停不停止由线程本身说了算,他只算是类似提个建议,我们可以通过interrupted()进行判断,从而手动停止线程

  6.wait和notify和notifyAll()

    他们为object的方法,调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。wait和释放锁,而sleep不会。

    在JUC下condition类下的的await() signal() signalAll()与上面类似,await可以指定等待条件也就更加灵活

三、IO

 

  1.字节流和字符流

    InputStream和outputstream是字节流,Reader和Writer是字符流,一个字符占用两个字节,所以在涉及中文时,应该采用字符流

  2.装饰者模式

    在io中使用的装饰者模式,通过封装多重接口来达到不同目的,这种方法更加灵活但也导致了javaio操作非常繁琐不像其他语言那样的方便使用

  3.序列化

    为了让对象在网络间进行传输,需要将他进行序列化转换为字节序列,通过实现Serializable接口,他可以实现轻量级持久性,在需要时进行反序列化转换为对象

  4.常用实例

     3.1 文件读取写入--复制

public static void copyFile(String src, String dist) throws IOException {
    FileInputStream in = new FileInputStream(src);
    FileOutputStream out = new FileOutputStream(dist);
    byte[] buffer = new byte[20 * 1024];
    int cnt;
    // read() 最多读取 buffer.length 个字节
    // 返回的是实际读取的个数
    // 返回 -1 的时候表示读到文件尾
    while ((cnt = in.read(buffer, 0, buffer.length)) != -1) {
        out.write(buffer, 0, cnt);
    }
    in.close();
    out.close();
}

     3.2 标准输入流的使用(在system.in封装过滤器)

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String readRecv = br.readLine();

    

 

posted @ 2019-04-29 13:26  JokerQ-  阅读(818)  评论(0编辑  收藏  举报