目录
一、IO流框架---commons-io
这个框架提供了很多关于IO流的操作api,比如复制文件、删除文件夹等,之前需要很多代码,导入io框架后一个api就能解决
public class Test { public static void main(String[] args) { try { //1.完成文件的复制 IOUtils.copy(new FileInputStream("src/twx.txt"),new FileOutputStream("src/YY.txt")); //2.拷贝文件到文件夹 FileUtils.copyDirectoryToDirectory(new File("C:\\Users\\TT\\Pictures\\Camera Roll"), new File("C:/")); //3.完成文件夹的复制到某个文件夹下 FileUtils.copyDirectoryToDirectory(new File("C:\\javalesson00007777"),new File("D:\\132")); //4.删除文件夹 FileUtils.delete(new File("D:\\132")); } catch (IOException e) { e.printStackTrace(); } } }
二、缓冲字符输入流
之前想将数据写入到文件中去,用的最原始的字节输出流(InputStream),但是很容易出现乱码(因为是按一个字节读入,而汉字占三个字节,所以就会出现乱码),并且效率也低;后来将其包装成高级管道--字节输入缓冲流(BufferReader),新增了按行读取的api(readLine),也的确是极大的增强了读取的性能.(注:有时候用缓冲流读写数据的时候,显示为空,可能是未使用调用flush()方法,数据阻塞在管道)
@Test public void InputStreamTest(){ try (java.io.InputStream is = new FileInputStream("src/twx.txt"); BufferedReader bf = new BufferedReader(new InputStreamReader(is))){ String line; while ((line = bf.readLine())!=null){ System.out.println(line); } } catch (Exception e) { System.out.println("文件路劲有误"); } }
三、打印流
想要数据写出到文件中去,最原始的方法是用字节输入流(OutputStream),但是效率也是很慢,并且一次也只能写一个字节,如果超过则会乱码;所以在写出的时候选用Print打引流只很方便且效率高的,几乎也不会出现乱码。
public class PrintTest { public static void main(String[] args) { try { PrintStream pt = new PrintStream(new FileOutputStream("src/twx.txt"), true);//true是选择不覆盖文件中已有的内容 pt.println(1); pt.println("张安"); pt.println(true); pt.println(23); pt.println("我是打印流,写啥打啥"); pt.close(); } catch (FileNotFoundException e) { System.out.println("文件路劲有误"); } } }
四、创建线程
创建方式一:继承Thread类,然后重写里面的run()方法,执行start方法;
方式二:实现Runnable接口,重写里面的run()方法,构建任务类 ;然后将任务类对象交给线程对类,执行start方法;
方式三:实现callable接口,在接口中重写call()方法,然后将实现callable接口的类交给FutureTask类,最后将FutureTask的对象交给线程类调用start方法;该创建方式中的call()方法是可以带有返回值的,所以该线程创建方式是可以返回一个结果,这个时候就可以让FutureTask对象调用get()方法得到返回结果(注:只有在子线程执行完了,get()方法才会被调用)
package day21.CreatThread; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; /** * */ public class CallableDemo { public static void main(String[] args) { //3.创建callable任务对象 Callable<Integer> callable = new MyCallable(100); /** * 4.结合FutureTask类,将callable任务对象封装在FutureTask中 */ FutureTask<Integer> f1 = new FutureTask<>(callable); //5.将FutureTask中的任务对象交给线程类 Thread thread = new Thread(f1); thread.start(); /** * 调用get方法得到子线程返回的结果 * 只在子线程执行完毕后才会调用get方法 */ try { System.out.println(Thread.currentThread().getName()+"线程计算的结果为:" + f1.get()); } catch (Exception e) { e.printStackTrace(); } } } //1.创建任务类,实现callable接口 class MyCallable implements Callable<Integer> { private int n; public MyCallable(int n) { this.n = n; } /** * 2.重写call方法,在其中定义子线程任务 * 其中可以返回数据(此处位计算1-n的和并返回) * @return * @throws Exception */ @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i < n; i++) { sum+=i; } return sum; } }
五、线程安全
当一个资源同时被两个子线程访问时,可能就会出现线程安全问题;这个地方就可以用到synchronized关键字,它可以修饰方法,或者将可能出现逻辑同步的地方使用块将其放入然后加入synchronized修饰;除此之外也可以用lock()和unlocak()放法上锁和开锁。
//取钱逻辑 //加了个锁,同时只能有一个人访问得到共享资源 public void takeMoney(double money) throws InterruptedException { String name = Thread.currentThread().getName(); //synchronized (this) { //锁对象都设为共享资源 lock.lock(); try { if(this.money>=money){ System.out.println(name +"取钱成功,吐出"+money); this.money-=money; System.out.println(name+"取钱后,剩余"+this.money); }else{ System.out.println(name+"来取钱,余额不足!"); } } finally { lock.unlock();//放在try...finally中,防止中间报错,不会解锁 } //} }
六、线程池
1.使用工具类直接创建一个固定核心线程的线程池
/** * 使用工具类创建一个线程池 * 大型并发系统使用该方法创建线程池会出现系统风险 * 小型项目常用四个工具类创建线程池: * newFixedThreadPool、SingleThreadPool -----允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量请求,导致OOM * newCachedThreadPool、ScheduledThreadPool ------允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,导致OOM * */ public class ExecutorsTest { public static void main(String[] args) { //直接创建三个核心线程,固定线程数 ExecutorService pool = Executors.newFixedThreadPool(3); pool.execute(new MyRunnableDemo1()); pool.execute(new MyRunnableDemo1()); pool.execute(new MyRunnableDemo1()); pool.execute(new MyRunnableDemo1());//次线程并没有被执行 只有三个核心线程---阻塞了 } }
2.线程池只能接受Runnable、Callable任务对象,在任务类中写子线程要做的事,然后线程池对象调用execute()执行Runnable中的任务,调用submit()执行Callable中的任务
public class ThreadPoolTest1 { public static void main(String[] args) { ExecutorService pool = new ThreadPoolExecutor(3, 5, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), new ThreadPoolExecutor.AbortPolicy()); // ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS, // new ArrayBlockingQueue<>(5),new ThreadPoolExecutor.AbortPolicy()); Runnable target = new MyRunnableDemo1(); pool.execute(target); pool.execute(target); pool.execute(target); } }-------------------------------------------------------------------------
ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),new ThreadPoolExecutor.AbortPolicy()); Future<Integer> submit1 = pool.submit(new MyCallableDemo2(100)); Future<Integer> submit2 = pool.submit(new MyCallableDemo2(200)); Future<Integer> submit3 = pool.submit(new MyCallableDemo2(300)); Future<Integer> submit4 = pool.submit(new MyCallableDemo2(400)); System.out.println(submit1.get()); System.out.println(submit2.get()); System.out.println(submit3.get()); System.out.println(submit4.get()); }
3.线程池七大参数
(1)核心线程数:线程池刚创建的时候,里面没有一个线程,当调用executor方法加入一个新的任务时,则会马上创建一个新的线程去执行这个任务;
(2)池中最大线程数:线程池允许存活的最大线程数量;
(3)空闲线程存活时间:当一个可被回收的线程(
- 设置allowCoreThreadTimeout=true的核心线程。
- 大于核心线程数的线程(非核心线程)。
)空闲超过设置的存活时间则会被回收;
(4)存活时间单位
(5)工作队列:当提交的任务大于核心线程数时,就会进入队列等到线程池调度;
(6)线程工厂:当添加一个任务时,核心线程和工作队列都已满,并且没有空闲线程,而且线程池也还没有达到最大线程数,此时就会创建新的线程;
(7)拒绝策略 :当线程池中的线程数已满,并且工作队列达到限制,新提交的任务使用拒绝策略处理。
4.线程池做为定时器对象
定时器也可用Timer来创建,但此时事一个单线程处理所有任务,任务之间容易造成影响;但是用线程池来作为定时器,然后调用scheduleAtFixedRate方法,在里面重写run()方法,写需要完成的任务则如果挂掉了一个线程其他的任务也可以被执行下去。
public class TimeTest { public static void main(String[] args) { ScheduledExecutorService pool = Executors.newScheduledThreadPool(3); pool.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在执行A任务"+new Date()); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } },0,2, TimeUnit.SECONDS); pool.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"正在执行B任务"+new Date()); } },0,2,TimeUnit.SECONDS); } }
七.Dom解析
这里主要是用dom4j解析XML文件。
(1)创建DOM解析器(new SAXReader())
(2)将xml文件解析成Document对象(调用解析器的read()方法,放入xml文件)
(3)获取根元素下的子元素(调用getRootElement()方法后再调用elements())
(4)取值(调用elementText()方法)
八.工厂模式
以往的方法都是通过new来产生一个对象,但是如果类和类直接存在关系,或者想要修改某个信息或功能时,则需要修改很多地方,工厂模式就解决了这些问题,实现了类的解耦。工厂模式就是创建一个类,里面写方法创建好类,后续想用某个类的话直接调用方法即可,迭代也很方便。
public class Factory { public static Computer creatComputer(String info){ switch (info){ case "mac" : Computer computer = new Mac(); computer.setName("鸿蒙"); computer.setPrice(5000); return computer; case "huawei": Computer computer1 = new HuaWei(); computer1.setName("华为"); computer1.setPrice(10000); return computer1; default: return null; } } }