29)单元测试:对软件中最小可测试单元进行检查和验证。通常是函数/方法。(已知代码结构进行的测试,是白盒测试,一般由程序员自己完成)。
集成测试:将多个单元相互作用,形成一个整体,对整体协调性进行测试。一般从最小单元开始,持续推进到单元之间的接口直到集成为一个完整的软件为止。
自动测试:用程序批量、反复的进行测试,并可自动检查程序是否满足预定的要求。
手动测试:手动执行、手动输入,手动检查结果是否满足预定的要求。
回归测试:修改旧代码以后,重新测试以确认修改没有引入新的错误或导致其他代码产生错误。
30)JUnit是一个Java语言的单元测试框架。测试框架比main函数测试策略更好,显示直观方便提高测试效率。JUnit可以单独存在,发布时不需要单独删除。每一个测试方法的头部加@Test,这样JUnit会自动执行这些测试方法。
import static 导入一个类中的所有静态方法。
31) 源文件建议采用UTF-8编码,和外界(文本文件)的输入输出尽量采用UTF-8编码。
Java的程序内部采用UTF-16编码储存所有字符(不受程序员控制)
32)多进程的优点:同时运行多个任务,当程序因IO堵塞时,可以释放CPU,让CPU充分工作。系统有多个CPU时,可以为多个程序同时服务。缺点:笨重,不易管理和切换。
33)多线程:一个程序可以包含多个子任务,可以串行和并行。每个子任务可以称为一个线程。如果一个子任务堵塞,程序可以将CPU调度另外一个子任务进行工作。CPU还是保留在本程序中,但本程序所获得CPU时间和利用率提高了。
34)多进程 对 多线程
- 线程共享数据
- 线程通讯更高效
- 线程更轻量级,更容易切换
- 多个线程更容易管理
35)多线程创建:线程继承Thread类,实现run方法。 线程实现Runnable接口,实现run方法。
public class Thread1 extends Thread{ public void run(){ System.out.println("Thread1"); } } public class Thread2 implements Runnable{ public void run(){ System.out.println("Thread2"); } }
启动时,Start方法会自动以新进程调用run方法,若直接调用run方法,会变成串行执行。
Start只能一次。多线程的启动先后顺序是随机的。
线程无需关闭,run方法结束后,线程自动关闭。main函数可能早于新线程结束,整个程序并不终止。而整个程序的终止是等所有线程都终止。(包括main函数线程)
Thread vs Runnable
- 1.Thread占据了父类的名额,不如Runable方便
- 2.Thread类实现Runable,继承了Thread类,本质上是实现Runable接口
- 3.Runable启动时需要Thread类的支持{Thread t = new Thread(tt); t.start();}(tt为实现了Runnable的对象)
- 4.Runable更容易实现多线程中资源共享
多线程信息共享:通过共享变量。1.static变量 2.同一个Runnable类的成员变量。但是只使用共享变量进行工作会出现问题 1.各线程的工作缓存副本数据不一致 2.关键步骤缺乏加锁限制。
比如,启动四个线程出售100张门票。由于线程并非直接从内存中进行数据读写,而是先加载入工作缓存中再进行操作。,所以i++,i–不是原子性操作,中间有着许多步骤。
例:读取主存i(正本)到工作缓存(副本)中,每个CPU执行(副本)i-1操作,CPU将结果写入到缓存(副本)中,数据再从工作缓存(副本)刷到主存(正本)中。这个问题同数据库中的并发问题相同。
变量副本问题采用volatile关键字修饰变量。 保证不同线程对共享变量操作时的可见性。
public class ThreadDemo2 { public static void main(String args[]) throws Exception { TestThread2 t = new TestThread2(); t.start(); Thread.sleep(2000); t.flag = false; System.out.println("main thread is exiting"); } } class TestThread2 extends Thread { boolean flag = true;//子线程不会停止 //volatile boolean flag = true;//用volatile修饰的变量可以及时在各线程里面通知 public void run() { int i=0; while(flag) { i++; } System.out.println("test thread3 is exiting"); } }
子线程内flag为boolean型时,主函数的t.flag = true命令不会被接收到。因为内存和工作缓存中的flag已经不同了,子线程工作缓存中的flag还是true的,对内存flag的修改无反应。
加锁限制:
- 1.互斥:某一线程运行代码段时,其他线程不能同时运行此代码段。
- 2.同步:多个线程的运行,必须按照某一种规定的先后顺序来运行。
- 3.互斥是同步的一种特例。
- Synchronized代码块/函数,只能一个线程进入。
- Synchronized加大性能负担,但是使用简便。
public class ThreadDemo3 { public static void main(String[] args) { TestThread3 t = new TestThread3(); new Thread(t, "Thread-0").start(); new Thread(t, "Thread-1").start(); new Thread(t, "Thread-2").start(); new Thread(t, "Thread-3").start(); } } class TestThread3 implements Runnable { private volatile int tickets = 100; //多个线程在共享的 String str = new String(""); public void run() { while (true) { sale(); try { Thread.sleep(100); } catch (Exception e) { System.out.println(e.getMessage()); } if (tickets <= 0) { break; } } } public synchronized void sale() { //同步函数 if (tickets > 0) { System.out.println(Thread.currentThread().getName() + " is saling ticket " + tickets--); } } }