傲渊山岳 发表于 2025-4-8 16:21:44

重温java 系列一 Java根本

文件拷贝的5种方式

传统字节拷贝

public static void main(String[] args) throws IOExecption{
    try(InputStream is = new FileInputStream("source.txt");
      OutputStream os = new FileOutputStream("target.txt")){
      
      byte[] buffer = new byte;
      int length;
      while ((length = is.read(buffer))>0){
            os.write(buffer,0,length);
      }
      
    }
}


[*]特点:根本方法,直接逐字节或缓冲区读写。
[*]效率: 最低 (得当小文件)
缓冲流优化拷贝

public static void main(String[] args) throws FileNotFoundException {
      try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("source.txt"));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("target.txt"))
      ){
            byte[] buffer = new byte;
            int len;
            while ((len = bis.read(buffer)) != -1) {
               bos.write(buffer, 0, len);
            }
      } catch (IOException e) {
            throw new RuntimeException(e);
      }
    }


[*]特点: 通过换红淘汰IO次数
[*]**效率:**比传统字节流提升2~5倍
Java NIO 拷贝

public static void main(String[] args) throws IOException {
      Path source = Paths.get("source.txt");
      Path target = Paths.get("target.txt");
      Files.copy(source,target, StandardCopyOption.REPLACE_EXISTING);

    }


[*]特点: 利用通道(Channel)直接传输数据
[*]**效率:**大文件性能最佳(利用了零拷贝技术)
内存映射文件拷贝

public static void main(String[] args) throws IOException {
      try (RandomAccessFile source = new RandomAccessFile("source.txt", "r");
             RandomAccessFile target = new RandomAccessFile("target.txt", "rw")) {
            FileChannel sourceChannel = source.getChannel();
            MappedByteBuffer buffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, 0, sourceChannel.size());
            target.getChannel().write(buffer);
      }


[*]**特点:**将文件映射到内存中直接操作
[*]**效率:**得当超大文件(实现复杂,需要审慎处置惩罚内存)
中断线程的三种方式

停止一个线程通常意味着在线程处置惩罚任务完成之前停掉正在做的操作,也就是放弃当前的操作。
在Java中有以下3种方式可以种植正在运行的线程:

[*]使用推出标志,使线程正常退出,也就是当run()方法完成后线程中断
[*]使用stop()方法强行停止线程,但是不保举使用此方法,该方法已被弃用
[*]使用interrupt 方法中断主线程
1. 使用标志位停止线程(保举)

在run()方法执行完毕后,该线程就停止了,但是在某些特殊情况下,run()方法中会被一直执行,好比在服务端步伐中可能会使用while(true){…}这样的循环结构来不断的接受来自客户端的请求,此时就可以用修改标志位的方式来竣事run 方法。
public class Main {

    private volatile boolean exitFlag = false;

    public void run(){
      while (!exitFlag){
            System.out.println("Thread is running.....");
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                System.out.println("Thread interrupted");
                Thread.currentThread().interrupt();
            }
      }
      System.out.println("Thread exiting.....");
    }


    public void stop(){
      exitFlag = true;
    }

   

    public static void main(String[] args) throws IOException, InterruptedException {
      Main main = new Main();
      Thread thread = new Thread(main::run);
      thread.start();
      Thread.sleep(1000);
      main.stop();
    }
}
2. 使用stop()中断线程(不保举)

Thread.stop()方法可以欺凌中断线程的执行,然而,这种方法是不安全的,因为他不能保证线程资源的准确释放和清理,可能导致数据不一致和资源泄露等标题,因此该方法已被官方弃用。
public class Main extends Thread{


    public void run(){
      while (true){
            System.out.println("Thread is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
//                throw new RuntimeException(e);
            }
      }
    }

    public static void main(String[] args) throws InterruptedException {
      Main main = new Main();
      main.start();
      Thread.sleep(5000);
      main.stop();
    }
}
通过JDK的Api,我们会看到java.lang.Thread 范例提供了一系列的方法,如start(),stop(),resume(),suspend(),destory()等方法来管理线程。但是除了start()之外,其他几个方法都被声明为已过时(@Deprecated)。
固然stop()方法确实可以停止一个正在运行的线程,但是这个方法 是不安全的,而且该方法已被弃用,最好不要使用它。
为什么弃用stop():

[*]调用stop()方法会立刻停止run()方法中剩余的全部工作,包罗在catch或者finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要表现的捕捉),因此可能会导致一些清理性的工作得不到完成,如文件、数据库等等的关闭操作。
[*]调用stop()方法会立刻释放该线程所持有的锁,导致数据得不到同步,导致数据不一致的标题。
使用interrupt()中断线程

现在我们知道了使用stop()方式停止线程黑白常不安全的方式,那么我们应该使用什么方法来停止线程呢?答案就是使用interrupt()方法来中断线程。
需要明确的一点是:interrupt()方法并不像在for循环语句中使用break语句那样干脆,立刻就停止循环。调用interrupt()方法仅仅是在当火线程中打一个停止的标记,并不是真的停止线程。
也就是说,线程中断并不会立刻停止线程,而是通知目的线程,有人盼望你停止,至于目的线程收到通知后会如何处置惩罚,则完全由目的线程自行据欸的那个,这一点很重要。如果中断后,线程立刻无条件推出,那么我们又会碰到stop()方法的老标题。
事实上,如果一个线程不能被interrupt,那么stop方法也不会起作用。
接下来我们看一个使用了interrupt()的例子:

public class Main extends Thread{
//    public static void main(String[] args)
//    {
//      SpringApplication.run(Main.class, args);
//    }


    @Override
    public void run() {
      super.run();
      for (int i = 0; i <10000; i++) {
            System.out.println("i="+i);

      }
    }

    public static void main(String[] args){


      try {
            Main t = new Main();
            t.start();
            Thread.sleep(1000);
            t.interrupt();
      } catch (InterruptedException e) {
            throw new RuntimeException(e);
      }


    }
}
结果如下:
i=9986
i=9987
i=9988
i=9989
i=9990
i=9991
i=9992
i=9993
i=9994
i=9995
i=9996
i=9997
i=9998
i=9999
从输出的结果我们会发现interrupt方法并没有停止线程t中的处置惩罚逻辑,也就是说纵然t线程被设置成了中断状态,但是这个中断并不会起作用,那么该如何停止该线程呢?
这就需要使用到别的两个与线程中断有关的方法了
public boolean Thread.isInterrupted() //判断是否被中断
public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态
这两个方法使得当火线程可以或许感知到是否被中断了(通过查抄标志位)
以是如果盼望线程t 在中断后停止,就必须先判断是否被中断,并为它增加相应的中断处置惩罚代码:
@Override
    public void run() {
      super.run();
      for (int i = 0; i <10000; i++) {
            if (Thread.currentThread().isInterrupted()){
                //处理中断逻辑
                break;
            }
            System.out.println("i="+i);

      }
    }
在上面这段代码中,我们增加了Thread.isInterrupted()来判断当火线程是否被中断了,如果是,则退出for 循环,竣事线程。
这种方式看起来与之前介绍的“使用标志位中断线程”非常类似,但是碰到了sleep()或者wait()这样的操作,我们只能通过中断来处置惩罚。
public static native sleep(long millis) throws InterrupedExecption
Thread.Sleep()方法会抛出一个InterruptedException 异常,当线程被sleep()休眠时 ,如果被中断,就会抛出这个异常。
   注意:Thread.sleep() 方法由于中断额抛出 的异常,是会清除中断标记的

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 重温java 系列一 Java根本