• Java Concurrency


    创建线程

    在 Java 中,创建线程有两种方式:

    • 继承 java.lang.Thread 类,重写 run 方法。
      public class MyJob extends Thread {
      
          @Override
          public void run() {
              System.out.println("Hello Thread");
          }
          
          public static void main(String[] args) {
              Thread thread = new MyJob();
              thread.start();
          }
      }
    • 实现 java.lang.Runnable 接口,然后在创建 Thread 实例时传入 Runnable 参数。
      public class MyJob implements Runnable {
          @Override
          public void run() {
              System.out.println("Hello Thread");
          }
          
          public static void main(String[] args) {
              Thread thread = new Thread(new MyJob());
              thread.start();
          }
      }

    获取和设置线程信息

    java.lang.Thread 类中的几个信息字段帮助我们来识别一个线程、观察线程的状态或是控制线程的优先级:

    • Id: 线程的 ID,每个线程拥有一个唯一的标识。
    • Name: 线程的名称。
    • Priority: 线程的优先级。优先级的范围是 1~10,值越大优先级越高。
    • State: 线程的状态。在 Java 中,线程有六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING 和 TERMINATED。

    上述的属性 java.lang.Thread 类都提供 getter 方法以获取线程的信息,其中 Id 和 State 是不可代码控制修改的,也不提供 setter 方法。

    获取当前正在运行的线程

    java.lang.Thread 类提供一个静态方法 currentThread(),该方法返回当前正在运行的线程。

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());    // main
    }

    线程休眠

    Thread 类的 sleep() 方法接收一个 long 参数 milliseconds,使得当前正在运行的线程休眠 milliseconds 毫秒。

    TimeUnit 类同样提供提供 sleep() 方法支持线程休眠。它接收各种时间单位并将其转换成微秒。

    try {
        TimeUnit.SECONDS.sleep(3);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    线程中断

    有时候,我们需要在线程任务执行完毕前取消线程任务,例如当下载文件超时时取消下载任务。当 interrupt() 方法被调用时,线程的中断状态被置为 true,但是线程并不会终止。可以利用 isInterrupted 方法检测线程是否中断,并以此对线程进行控制。

    public static void main(String[] args) throws Exception {
            
        Thread task = new Thread(new Runnable() {
            public void run() {
                int num = 2;
                while (!Thread.currentThread().isInterrupted()) {
                    if (Primes.isPrime(num)) {
                        System.out.println(String.format("Number %d is Prime", num));
                    }
                    num++;
                }
            }
        });
        
        task.start();
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        task.interrupt();
        
    }

    Thread 类还提供一个静态的 interrupted() 方法来判断当前正在运行的线程是否中断。但是 interrupted() 与 isInterrupted() 有些差异:isInterrupted() 方法不会修改中断状态;而 interrupted() 方法会将中断状态置为 true。 

    有时线程执行的任务十分复杂,使用异常控制会比条件控制更加可取。

    /**
     * This class search for files with a name in a directory
     */
    public class FileSearch implements Runnable {
    
        private String initPath;    // Initial path for the search
        private String fileName;    // Name of the file we are searching for
    
        public FileSearch(String initPath, String fileName) {
            this.initPath = initPath;
            this.fileName = fileName;
        }
    
        /**
         * Main method of the class
         */
        @Override
        public void run() {
            File file = new File(initPath);
            if (file.isDirectory()) {
                try {
                    directoryProcess(file);
                } catch (InterruptedException e) {
                    System.out.printf("%s: The search has been interrupted", Thread.currentThread().getName());
                    cleanResources();
                }
            }
        }
    
        /**
         * Method for cleaning the resources. In this case, is empty
         */
        private void cleanResources() {
            
        }
    
        /**
         * Method that process a directory
         * 
         * @param file
         *            : Directory to process
         * @throws InterruptedException
         *            : If the thread is interrupted
         */
        private void directoryProcess(File file) throws InterruptedException {
    
            // Get the content of the directory
            File list[] = file.listFiles();
            if (list != null) {
                for (int i = 0; i < list.length; i++) {
                    if (list[i].isDirectory()) {
                        // If is a directory, process it
                        directoryProcess(list[i]);
                    } else {
                        // If is a file, process it
                        fileProcess(list[i]);
                    }
                }
            }
            // Check the interruption
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
        }
    
        /**
         * Method that process a File
         * 
         * @param file
         *            : File to process
         * @throws InterruptedException
         *             : If the thread is interrupted
         */
        private void fileProcess(File file) throws InterruptedException {
            // Check the name
            if (file.getName().equals(fileName)) {
                System.out.printf("%s : %s
    ", Thread.currentThread().getName() ,file.getAbsolutePath());
            }
    
            // Check the interruption
            if (Thread.interrupted()) {
                throw new InterruptedException();
            }
        }
    
        
        /**
         * Main method of the core. Search for the autoexect.bat file
         * on the Windows root folder and its subfolders during ten seconds
         * and then, interrupts the Thread
         * @param args
         */
        public static void main(String[] args) {
            // Creates the Runnable object and the Thread to run it
            FileSearch searcher=new FileSearch("C:\","CHAINLOG.log.2016092210");
            Thread thread=new Thread(searcher);
            
            // Starts the Thread
            thread.start();
            
            // Wait for ten seconds
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            // Interrupts the thread
            thread.interrupt();
        }
    }

    join - 等待线程结束

    在某些情况下,需要等待某一线程执行完毕后当前的线程才能继续执行,例如等待某个资源初始化完毕后才能执行后续的操作。 Thread 类提供了 join() 方法来实现此功能。当在线程 thread1 中调用 thread2.join() 方法,那么 thread1 线程将会挂起直至线程 thread2 结束。

    Example:

    public static void main(String[] args) throws Exception {
            
        Thread dataSourcesLoader = new Thread(new Runnable() {
            public void run() {
                System.out.printf("Begining data sources loading: %s
    ",new Date());
                try {
                    TimeUnit.SECONDS.sleep(4);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.printf("Data sources loading has finished: %s
    ",new Date());
            }
        });
        
        Thread networkConnectionsLoader = new Thread(new Runnable() {        
            @Override
            public void run() {
                System.out.printf("Begining network connections loading: %s
    ",new Date());
                try {
                    TimeUnit.SECONDS.sleep(6);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.printf("Network connections loading has finished: %s
    ",new Date());
            }
        });
        
        dataSourcesLoader.start();
        networkConnectionsLoader.start();
        
        dataSourcesLoader.join();
        networkConnectionsLoader.join();
        System.out.printf("Main: Configuration has been loaded: %s
    ",new Date());
    }

    jion 还有两个重载的方法:join (long milliseconds) 和 join (long milliseconds, long nanos)。第一个方法接收一个 long 参数 milliseconds,如果在线程 thread1 中调用代码 thread2.join(1000),则 thread1 线程挂起直至当 thread2 线程执行完毕;或者当 1000 毫秒过去后,即使 thread2 仍未执行完毕,thread1 依然停止挂起,继续执行。

    守护进程

    在线程启动前调用 setDaemon(true) 可以将线程设置为守护进程。

  • 相关阅读:
    教你彻底弄懂JS中this的指向
    js-原型,原型链
    Firefox SyntaxError: invalid regexp group ChunkLoadError: Loading chunk task-show-task-show-module failed.
    什么是标签语义化?标签语义化有什么意义?
    什么是事件委托?jquery和js怎么去实现?
    express框架
    es6
    node搭建服务器
    node内容
    ajax面试题
  • 原文地址:https://www.cnblogs.com/huey/p/5888810.html
Copyright © 2020-2023  润新知