java进程_java进程慢怎么分析 - CSDN
  • java进程

    2018-09-16 10:53:51
    Java创建进程 1 进程的概念 1  ...2.1 JAVA进程的创建 1  2.1.1 ProcessBuilder 2  2.1.2 Runtime 3  2.1.3 Process 4  2.2 实例 5  2.2.1 创建子进程 5  2.2.2 进程阻塞问题 7  2.2.3 在jav...

    Java创建进程


    1 进程的概念 1 
    1.1 进程的概念 1 
    1.2 进程的特征 1 
    1.3 进程与线程区别 1 
    2 进程的创建 1 
    2.1 JAVA进程的创建 1 
    2.1.1 ProcessBuilder 2 
    2.1.2 Runtime 3 
    2.1.3 Process 4 
    2.2 实例 5 
    2.2.1 创建子进程 5 
    2.2.2 进程阻塞问题 7 
    2.2.3 在java中执行java程序 11 



    1 进程的概念 
    1.1 进程的概念 
      进程是操作系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;可以分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元。 
      第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。 
      第 二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。 
    1.2 进程的特征 
        动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。 
        并发性:任何进程都可以同其他进程一起并发执行 
        独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位; 
        异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进 
        结构特征:进程由程序、数据和进程控制块三部分组成。 
        多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。 
    1.3 进程与线程区别 
        进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影 响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程 序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进 程。 

    2 进程的创建 
    2.1 Java进程的创建 
    Java提供了两种方法用来启动进程或其它程序: 
    (1)使用Runtime的exec()方法 
    (2)使用ProcessBuilder的start()方法 
    2.1.1 ProcessBuilder 
       ProcessBuilder类是J2SE 1.5在java.lang中新添加的一个新类,此类用于创建操作系统进程,它提供一种启动和管理进程(也就是应用程序)的方法。在J2SE 1.5之前,都是由Process类处来实现进程的控制管理。 
    每个 ProcessBuilder 实例管理一个进程属性集。start() 方法利用这些属性创建一个新的 Process 实例。start() 方法可以从同一实例重复调用,以利用相同的或相关的属性创建新的子进程。 
    每个进程生成器管理这些进程属性: 
      命令 是一个字符串列表,它表示要调用的外部程序文件及其参数(如果有)。在此,表示有效的操作系统命令的字符串列表是依赖于系统的。例如,每一个总体变量,通 常都要成为此列表中的元素,但有一些操作系统,希望程序能自己标记命令行字符串——在这种系统中,Java 实现可能需要命令确切地包含这两个元素。 
      环境 是从变量 到值 的依赖于系统的映射。初始值是当前进程环境的一个副本(请参阅 System.getenv())。 
    工作目录。默认值是当前进程的当前工作目录,通常根据系统属性 user.dir 来命名。 
      redirectErrorStream 属性。最初,此属性为 false,意思是子进程的标准输出和错误输出被发送给两个独立的流,这些流可以通过 Process.getInputStream() 和 Process.getErrorStream() 方法来访问。如果将值设置为 true,标准错误将与标准输出合并。这使得关联错误消息和相应的输出变得更容易。在此情况下,合并的数据可从 Process.getInputStream() 返回的流读取,而从 Process.getErrorStream() 返回的流读取将直接到达文件尾。 
    修 改进程构建器的属性将影响后续由该对象的 start() 方法启动的进程,但从不会影响以前启动的进程或 Java 自身的进程。大多数错误检查由 start() 方法执行。可以修改对象的状态,但这样 start() 将会失败。例如,将命令属性设置为一个空列表将不会抛出异常,除非包含了 start()。 
    注意,此类不是同步的。如果多个线程同时访问一个 ProcessBuilder,而其中至少一个线程从结构上修改了其中一个属性,它必须 保持外部同步。 

    构造方法摘要  
    ProcessBuilder(List<String> command)   
              利用指定的操作系统程序和参数构造一个进程生成器。    
    ProcessBuilder(String... command)   
              利用指定的操作系统程序和参数构造一个进程生成器。    
      
    方法摘要  
     List<String> command()   
              返回此进程生成器的操作系统程序和参数。  
     ProcessBuilder command(List<String> command)   
              设置此进程生成器的操作系统程序和参数。  
     ProcessBuilder command(String... command)   
              设置此进程生成器的操作系统程序和参数。  
     File directory()   
              返回此进程生成器的工作目录。  
     ProcessBuilder directory(File directory)   
              设置此进程生成器的工作目录。  
     Map<String,String> environment()   
              返回此进程生成器环境的字符串映射视图。  
     boolean redirectErrorStream()   
              通知进程生成器是否合并标准错误和标准输出。  
     ProcessBuilder redirectErrorStream(boolean redirectErrorStream)   
              设置此进程生成器的 redirectErrorStream 属性。  
     Process start()   
              使用此进程生成器的属性启动一个新进程。  

    2.1.2 Runtime 
      每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。 
      应用程序不能创建自己的 Runtime 类实例。但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用。一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为。 

    void addShutdownHook(Thread hook)   
              注册新的虚拟机来关闭挂钩。  
     int availableProcessors()   
              向 Java 虚拟机返回可用处理器的数目。  
     Process exec(String command)   
              在单独的进程中执行指定的字符串命令。  
     Process exec(String[] cmdarray)   
              在单独的进程中执行指定命令和变量。  
     Process exec(String[] cmdarray, String[] envp)   
              在指定环境的独立进程中执行指定命令和变量。  
     Process exec(String[] cmdarray, String[] envp, File dir)   
              在指定环境和工作目录的独立进程中执行指定的命令和变量。  
     Process exec(String command, String[] envp)   
              在指定环境的单独进程中执行指定的字符串命令。  
     Process exec(String command, String[] envp, File dir)   
              在有指定环境和工作目录的独立进程中执行指定的字符串命令。  
     void exit(int status)   
              通过启动虚拟机的关闭序列,终止当前正在运行的 Java 虚拟机。  
     long freeMemory()   
              返回 Java 虚拟机中的空闲内存量。  
     void gc()   
              运行垃圾回收器。  
     InputStream getLocalizedInputStream(InputStream in)   
              已过时。 从 JDK 1.1 开始,将本地编码字节流转换为 Unicode 字符流的首选方法是使用 InputStreamReader 和 BufferedReader 类。  
     OutputStream getLocalizedOutputStream(OutputStream out)   
              已过时。 从 JDK 1.1 开始,将 Unicode 字符流转换为本地编码字节流的首选方法是使用 OutputStreamWriter、BufferedWriter 和 PrintWriter 类。  
    static Runtime getRuntime()   
              返回与当前 Java 应用程序相关的运行时对象。  
     void halt(int status)   
              强行终止目前正在运行的 Java 虚拟机。  
     void load(String filename)   
              加载作为动态库的指定文件名。  
     void loadLibrary(String libname)   
              加载具有指定库名的动态库。  
     long maxMemory()   
              返回 Java 虚拟机试图使用的最大内存量。  
     boolean removeShutdownHook(Thread hook)   
              取消注册某个先前已注册的虚拟机关闭挂钩。  
     void runFinalization()   
              运行挂起 finalization 的所有对象的终止方法。  
    static void runFinalizersOnExit(boolean value)   
              已过时。 此方法本身具有不安全性。它可能对正在使用的对象调用终结方法,而其他线程正在操作这些对象,从而导致不正确的行为或死锁。  
     long totalMemory()   
              返回 Java 虚拟机中的内存总量。  
     void traceInstructions(boolean on)   
              启用/禁用指令跟踪。  
     void traceMethodCalls(boolean on)   
              启用/禁用方法调用跟踪。  

    2.1.3 Process 
    不管通过那种方法启动进程后,都会返回一个Process类的实例代表启动的进程,该实例可用来控制进程并获得相关信息。Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法: 

    void destroy()   
              杀掉子进程。  
             一般情况下,该方法并不能杀掉已经启动的进程,不用为好。  
    int exitValue()   
              返回子进程的出口值。   
              只有启动的进程执行完成、或者由于异常退出后,exitValue()方法才会有正常的返回值,否则抛出异常。  
    InputStream getErrorStream()   
              获取子进程的错误流。  
             如果错误输出被重定向,则不能从该流中读取错误输出。  
    InputStream getInputStream()   
              获取子进程的输入流。  
              可以从该流中读取进程的标准输出。  
    OutputStream getOutputStream()   
              获取子进程的输出流。  
              写入到该流中的数据作为进程的标准输入。  
    int waitFor()   
              导致当前线程等待,如有必要,一直要等到由该 Process 对象表示的进程已经终止。  

    通过该类提供的方法,可以实现与启动的进程之间通信,达到交互的目的。 


    2.2 实例 

    2.2.1 创建子进程 
    要创建子进程可以通过使用使用ProcessBuilder的start()方法和Runtime的exec()方法。 
    (1)Runtime.exec() 

    import java.io.BufferedReader;  
    import java.io.File;  
    import java.io.InputStreamReader;  
      
    public class Test1 {  
    public static void main(String[] args) {  
       try {  
        Process p = null;  
        String line = null;  
        BufferedReader stdout = null;  
      
        //list the files and directorys under C:\  
        p = Runtime.getRuntime().exec("CMD.exe /C dir", null, new File("C:\\"));  
        stdout = new BufferedReader(new InputStreamReader(p  
          .getInputStream()));  
        while ((line = stdout.readLine()) != null) {  
         System.out.println(line);  
        }  
        stdout.close();  
      
        //echo the value of NAME  
        p = Runtime.getRuntime().exec("CMD.exe /C echo %NAME%", new String[] {"NAME=TEST"});     
        stdout = new BufferedReader(new InputStreamReader(p  
          .getInputStream()));  
        while ((line = stdout.readLine()) != null) {  
         System.out.println(line);  
        }  
        stdout.close();  
       } catch (Exception e) {  
        e.printStackTrace();  
       }  
    }  

    (2)ProcessBuilder

    import java.io.BufferedReader;  
    import java.io.File;  
    import java.io.InputStreamReader;  
    import java.util.ArrayList;  
    import java.util.List;  
      
    public class Test2 {  
    public static void main(String[] args) {  
       try {  
        List<String> list = new ArrayList<String>();  
        ProcessBuilder pb = null;  
        Process p = null;  
        String line = null;  
        BufferedReader stdout = null;  
         
        //list the files and directorys under C:\  
        list.add("CMD.EXE");  
        list.add("/C");  
        list.add("dir");  
        pb = new ProcessBuilder(list);  
        pb.directory(new File("C:\\"));  
        p = pb.start();  
         
        stdout = new BufferedReader(new InputStreamReader(p  
          .getInputStream()));  
        while ((line = stdout.readLine()) != null) {  
         System.out.println(line);  
        }  
        stdout.close();  
      
        //echo the value of NAME  
        pb = new ProcessBuilder();  
        pb.command(new String[] {"CMD.exe", "/C", "echo %NAME%"});  
        pb.environment().put("NAME", "TEST");  
        p = pb.start();  
         
        stdout = new BufferedReader(new InputStreamReader(p  
          .getInputStream()));  
        while ((line = stdout.readLine()) != null) {  
         System.out.println(line);  
        }  
        stdout.close();  
       } catch (Exception e) {  
        e.printStackTrace();  
       }  
    }  

    从启动其他程序的Java进程看,已启动的其他程序输出就是一个普通的输入流,可以通过getInputStream()和getErrorStream 来获取。对于一般输出文本的进程来说,可以将InputStream封装成BufferedReader,然后就可以一行一行的对进程的标准输出进行处 理。 
        通常,一个程序/进程在执行结束后会向操作系统返回一个整数值,0一般代表执行成功,非0表示执行出现问题。有两种方式可以用来获取进程的返回值。一是利 用waitFor(),该方法是阻塞的,执导进程执行完成后再返回。该方法返回一个代表进程返回值的整数值。另一个方法是调用exitValue()方 法,该方法是非阻塞的,调用立即返回。但是如果进程没有执行完成,则抛出异常。 


    2.2.2 进程阻塞问题 
      由Process代表的进程在某些平台上有时候并不能很好的工作,特别是在对代表进程的标准输入流、输出流和错误输出进行操作时,如果使用不慎,有可能导致进程阻塞,甚至死锁。 
    如果将以上事例中的从标准输出重读取信息的语句修改为从错误输出流中读取: 
        stdout = new BufferedReader(new InputStreamReader(p.getErrorStream())); 
      那么程序将发生阻塞,不能执行完成,而是hang在那里。 
      当进程启动后,就会打开标准输出流和错误输出流准备输出,当进程结束时,就会关闭他们。在以上例子中,错误输出流没有数据要输出,标准输出流中有数据输 出。由于标准输出流中的数据没有被读取,进程就不会结束,错误输出流也就不会被关闭,因此在调用readLine()方法时,整个程序就会被阻塞。为了解 决这个问题,可以根据输出的实际先后,先读取标准输出流,然后读取错误输出流。 
       但是,很多时候不能很明确的知道输出的先后,特别是要操作标准输入的时候,情况就会更为复杂。这时候可以采用线程来对标准输出、错误输出和标准输入进行分别处理,根据他们之间在业务逻辑上的关系决定读取那个流或者写入数据。 
       针对标准输出流和错误输出流所造成的问题,可以使用ProcessBuilder的redirectErrorStream()方法将他们合二为一,这时候只要读取标准输出的数据就可以了。 
    当在程序中使用Process的waitFor()方法时,特别是在读取之前调用waitFor()方法时,也有可能造成阻塞。可以用线程的方法来解决这个问题,也可以在读取数据后,调用waitFor()方法等待程序结束。 
    总之,解决阻塞的方法应该有两种: 
    (1)使用ProcessBuilder类,利用redirectErrorStream方法将标准输出流和错误输出流合二为一,在用start()方法启动进程后,先从标准输出中读取数据,然后调用waitFor()方法等待进程结束。 
    如: 

    import java.io.BufferedReader;  
    import java.io.File;  
    import java.io.InputStreamReader;  
    import java.util.ArrayList;  
    import java.util.List;  
      
    public class Test3 {  
    public static void main(String[] args) {  
       try {  
        List<String> list = new ArrayList<String>();  
        ProcessBuilder pb = null;  
        Process p = null;  
        String line = null;  
        BufferedReader stdout = null;  
        //list the files and directorys under C:\  
        list.add("CMD.EXE");  
        list.add("/C");  
        list.add("dir1");  
        pb = new ProcessBuilder(list);  
        pb.directory(new File("C:\\"));  
        //merge the error output with the standard output  
        pb.redirectErrorStream(true);  
        p = pb.start();  
        //read the standard output  
        stdout = new BufferedReader(new InputStreamReader(p  
          .getInputStream()));  
        while ((line = stdout.readLine()) != null) {  
         System.out.println(line);  
        }  
        int ret = p.waitFor();  
        System.out.println("the return code is " + ret);  
        stdout.close();  
       } catch (Exception e) {  
        e.printStackTrace();  
       }  
    }  

    (2)使用线程

    import java.util.*;  
    import java.io.*;  
      
    class StreamWatch extends Thread {  
    InputStream is;  
    String type;  
    List<String> output = new ArrayList<String>();  
    boolean debug = false;  
    StreamWatch(InputStream is, String type) {  
       this(is, type, false);  
    }  
      
    StreamWatch(InputStream is, String type, boolean debug) {  
       this.is = is;  
       this.type = type;  
       this.debug = debug;  
    }  
      
    public void run() {  
       try {  
        PrintWriter pw = null;  
        InputStreamReader isr = new InputStreamReader(is);  
        BufferedReader br = new BufferedReader(isr);  
        String line = null;  
        while ((line = br.readLine()) != null) {  
         output.add(line);  
         if (debug)  
          System.out.println(type + ">" + line);  
        }  
        if (pw != null)  
         pw.flush();  
       } catch (IOException ioe) {  
        ioe.printStackTrace();  
       }  
    }  
      
    public List<String> getOutput() {  
       return output;  
    }  
    }  
    public class Test5 {  
    public static void main(String args[]) {  
       try {  
        List<String> list = new ArrayList<String>();  
        ProcessBuilder pb = null;  
        Process p = null;  
        // list the files and directorys under C:\  
        list.add("CMD.EXE");  
        list.add("/C");  
        list.add("dir1");  
        pb = new ProcessBuilder(list);  
        pb.directory(new File("C:\\"));  
        p = pb.start();  
      
        // process error and output message  
        StreamWatch errorWatch = new StreamWatch(p.getErrorStream(),  
          "ERROR");  
        StreamWatch outputWatch = new StreamWatch(p.getInputStream(),  
          "OUTPUT");  
        // start to watch  
        errorWatch.start();  
        outputWatch.start();  
        //wait for exit  
        int exitVal = p.waitFor();  
        //print the content from ERROR and OUTPUT  
        System.out.println("ERROR: " + errorWatch.getOutput());  
        System.out.println("OUTPUT: " + outputWatch.getOutput());  
        System.out.println("the return code is " + exitVal);  
       } catch (Throwable t) {  
        t.printStackTrace();  
       }  
    }  
    }  

    2.2.3 在java中执行java程序 
    执行一个Java程序的关键在于: 
    (1)知道JAVA虚拟机的位置,即java.exe或者java的路径 
    (2)知道要执行的java程序的位置 
    (3)知道该程序所依赖的其他类的位置 
    举一个例子,一目了然。 
    (1)待执行的Java类 

    public class MyTest {  
    public static void main(String[] args) {  
       System.out.println("OUTPUT one");  
       System.out.println("OUTPUT two");  
       System.err.println("ERROR 1");  
       System.err.println("ERROR 2");    
       for(int i = 0; i < args.length; i++)  
       {  
        System.out.printf("args[%d] = %s.", i, args[i]);  
       }  
    }  
    }  

    (2)执行该类的程序 

    import java.util.*;  
    import java.io.*;  
      
    class StreamWatch extends Thread {  
    InputStream is;  
    String type;  
    List<String> output = new ArrayList<String>();  
    boolean debug = false;  
      
    StreamWatch(InputStream is, String type) {  
       this(is, type, false);  
    }  
      
    StreamWatch(InputStream is, String type, boolean debug) {  
       this.is = is;  
       this.type = type;  
       this.debug = debug;  
    }  
      
    public void run() {  
       try {  
        PrintWriter pw = null;  
        InputStreamReader isr = new InputStreamReader(is);  
        BufferedReader br = new BufferedReader(isr);  
        String line = null;  
        while ((line = br.readLine()) != null) {  
         output.add(line);  
         if (debug)  
          System.out.println(type + ">" + line);  
        }  
        if (pw != null)  
         pw.flush();  
       } catch (IOException ioe) {  
        ioe.printStackTrace();  
       }  
    }  
      
    public List<String> getOutput() {  
       return output;  
    }  
    }  
    public class Test6 {  
    public static void main(String args[]) {  
       try {  
        List<String> list = new ArrayList<String>();  
        ProcessBuilder pb = null;  
        Process p = null;  
         
        String java = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";  
        String classpath = System.getProperty("java.class.path");  
        // list the files and directorys under C:\  
        list.add(java);  
        list.add("-classpath");  
        list.add(classpath);  
        list.add(MyTest.class.getName());  
        list.add("hello");  
        list.add("world");  
        list.add("good better best");  
         
        pb = new ProcessBuilder(list);  
        p = pb.start();  
         
        System.out.println(pb.command());  
        // process error and output message  
        StreamWatch errorWatch = new StreamWatch(p.getErrorStream(),  
          "ERROR");  
        StreamWatch outputWatch = new StreamWatch(p.getInputStream(),  
          "OUTPUT");  
        // start to watch  
        errorWatch.start();  
        outputWatch.start();  
        //wait for exit  
        int exitVal = p.waitFor();  
        //print the content from ERROR and OUTPUT  
        System.out.println("ERROR: " + errorWatch.getOutput());  
        System.out.println("OUTPUT: " + outputWatch.getOutput());  
        System.out.println("the return code is " + exitVal);  
       } catch (Throwable t) {  
        t.printStackTrace();  
       }  

     

    展开全文
  • Java进程&线程(一)

    2017-08-19 16:30:05
    Java进程&线程

    Java进程&线程

     

    程序:程序员写的代码,就是代码,不运行好像不会发生什么;

     

    进程:一个进程可以理解为运行的一个程序,当我们启动一个java程序后,对应的jvm就会创建一个进程;

     

    线程:jvm有一个进程,然而程序的实际执行是通过线程来完成的,进程之间是相互独立的,而线程之间是共享进程的资源的,就是说,进程是由n个线程组成的,而main函数就是进程创建后启动的主线程,另外,有一个用于垃圾回收的线程也是会事先启动的,所以说,一个java程序运行后,至少包含了2个线程(可能还会有其它的);

     

    实现多线程的几种方式:最常用的,继承Thread或者实现Runnable接口,还有我们可能不怎么熟悉的使用ExecutorServiceCallableFuture实现有返回结果的多线程,它们都是属于Executor框架中的功能类,可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须实现Runnable接口。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了;

     

    线程池概念的好处:pool,顾名思义,就是一个容器,装了很多线程,一般来说,降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗,提高响应速度:任务到达时不需要等待线程创建就可以立即执行,提高线程的可管理性:线程池可以统一管理、分配、调优和监控,这3点是我们看重的;

     

    Executor框架:Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,ExecutorExecutorsExecutorServiceCompletionServiceFutureCallable等,并发编程的一种编程方式是把任务拆分为一些列的小任务,即Runnable,然后再提交给一个Executor执行,Executor.execute(Runnalbe)Executor在执行时使用内部的线程池完成操作。CompletionService:调用CompletionServicetake方法时,会返回按完成顺序放回任务的结果,CompletionService内部维护了一个阻塞队列BlockingQueue,如果没有任务完成,take()方法也会阻塞;

     

    一个例子:

    public class ConcurrentCalculator {
    
    	private ExecutorService exec;
    	private int cpuCoreNumber;
    	private List<Future<Long>> tasks = new ArrayList<Future<Long>>();
    
    	// 内部类
    	class SumCalculator implements Callable<Long> {
    		private int[] numbers;
    		private int start;
    		private int end;
    
    		public SumCalculator(final int[] numbers, int start, int end) {
    			this.numbers = numbers;
    			this.start = start;
    			this.end = end;
    		}
    
    		public Long call() throws Exception {
    			Long sum = 0l;
    			for (int i = start; i < end; i++) {
    				sum += numbers[i];
    			}
    			return sum;
    		}
    	}
    
    	public ConcurrentCalculator() {
    		cpuCoreNumber = Runtime.getRuntime().availableProcessors();
    		exec = Executors.newFixedThreadPool(cpuCoreNumber);
    	}
    
    	public Long sum(final int[] numbers) {
    		// 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor
    		for (int i = 0; i < cpuCoreNumber; i++) {
    			int increment = numbers.length / cpuCoreNumber + 1;
    			int start = increment * i;
    			int end = increment * i + increment;
    			if (end > numbers.length)
    				end = numbers.length;
    			SumCalculator subCalc = new SumCalculator(numbers, start, end);
    			FutureTask<Long> task = new FutureTask<Long>(subCalc);
    			tasks.add(task);
    			if (!exec.isShutdown()) {
    				exec.submit(task);
    			}
    		}
    		return getResult();
    	}
    
    	/**
    	 * 迭代每个只任务,获得部分和,相加返回
    	 * 
    	 * @return
    	 */
    	public Long getResult() {
    		Long result = 0l;
    		for (Future<Long> task : tasks) {
    			try {
    				// 如果计算未完成则阻塞
    				Long subSum = task.get();
    				result += subSum;
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			} catch (ExecutionException e) {
    				e.printStackTrace();
    			}
    		}
    		return result;
    	}
    
    	public void close() {
    		exec.shutdown();
    	}
    }

    使用CompletionService改进:

    public class ConcurrentCalculator2 {
    
    	private ExecutorService exec;
    	private CompletionService<Long> completionService;
    
    	private int cpuCoreNumber;
    
    	// 内部类
    	class SumCalculator implements Callable<Long> {
    		private int[] numbers;
    		private int start;
    		private int end;
    
    		public SumCalculator(final int[] numbers, int start, int end) {
    			this.numbers = numbers;
    			this.start = start;
    			this.end = end;
    		}
    
    		public Long call() throws Exception {
    			Long sum = 0l;
    			for (int i = start; i < end; i++) {
    				sum += numbers[i];
    			}
    			return sum;
    		}
    	}
    
    	public ConcurrentCalculator2() {
    		cpuCoreNumber = Runtime.getRuntime().availableProcessors();
    		exec = Executors.newFixedThreadPool(cpuCoreNumber);
    		completionService = new ExecutorCompletionService<Long>(exec);
    
    	}
    
    	public Long sum(final int[] numbers) {
    		// 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor
    		for (int i = 0; i < cpuCoreNumber; i++) {
    			int increment = numbers.length / cpuCoreNumber + 1;
    			int start = increment * i;
    			int end = increment * i + increment;
    			if (end > numbers.length)
    				end = numbers.length;
    			SumCalculator subCalc = new SumCalculator(numbers, start, end);
    			if (!exec.isShutdown()) {
    				completionService.submit(subCalc);
    
    			}
    
    		}
    		return getResult();
    	}
    
    	/**
    	 * 迭代每个只任务,获得部分和,相加返回
    	 * 
    	 * @return
    	 */
    	public Long getResult() {
    		Long result = 0l;
    		for (int i = 0; i < cpuCoreNumber; i++) {
    			try {
    				Long subSum = completionService.take().get();
    				result += subSum;
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			} catch (ExecutionException e) {
    				e.printStackTrace();
    			}
    		}
    		return result;
    	}
    
    	public void close() {
    		exec.shutdown();
    	}
    }


    ThreadPoolExecutor它是一个ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用Executors工厂方法配置;当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程,当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行,当workQueue已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务,当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理,当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程,当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭;



    Executors提供的线程池配置方案,从而生成不同的ExecutorService


    注意非阻塞队列和阻塞队列,无界和有界队列:用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM,如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交,保证不抛弃一个任务,最大线程数一般设为2N+1最好,NCPU核数,核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数,如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果;

     

    线程安全:线程安全无非是要控制多个线程对某个资源的访问或修改,感觉这个说的非常明了,对于java的内存模型来说,要解决可见性和有序性;

    那么,何谓可见性?多个线程之间是不能互相传递数据通信的,它们之间的沟通只能通过共享变量来进行。Java内存模型(JMM)规定了jvm有主内存,主内存是多个线程共享的。当new一个对象的时候,也是被分配在主内存中,每个线程都有自己的工作内存,工作内存存储了主存的某些对象的副本,当然线程的工作内存大小是有限制的。当线程操作某个对象时,执行顺序如下:

    (1) 从主存复制变量到当前工作内存 (read and load)

    (2) 执行代码,改变共享变量值 (use and assign)

    (3) 用工作内存数据刷新主存相关内容 (store and write)

    JVM规范定义了线程对主存的操作指令:readloaduseassignstorewrite。当一个共享变量在多个线程的工作内存中都有副本时,如果一个线程修改了这个共享变量,那么其他线程应该能够看到这个被修改后的值,这就是多线程的可见性问题。

    那么,什么是有序性呢?线程在引用变量时不能直接从主内存中引用,如果线程工作内存中没有该变量,则会从主内存中拷贝一个副本到工作内存中,这个过程为read-load,完成后线程会引用该副本。当同一线程再度引用该字段时,有可能重新从主存中获取变量副本(read-load-use),也有可能直接引用原来的副本(use),也就是说readloaduse顺序可以由JVM实现系统决定。

    线程不能直接为主存中中字段赋值,它会将值指定给工作内存中的变量副本(assign),完成后这个变量副本会同步到主存储区(store- write),至于何时同步过去,根据JVM实现系统决定,有的字段,则会从主内存中将该字段赋值到工作内存中,这个过程为read-load,完成后线程会引用该变量副本,当同一线程多次重复对字段赋值时,比如:

    for(int i=0;i<10;i++)  

     a++;

    线程有可能只对工作内存中的副本进行赋值,只到最后一次赋值后才同步到主存储区,所以assign,store,weite顺序可以由JVM实现系统决定。假设有一个共享变量x,线程a执行x=x+1。从上面的描述中可以知道x=x+1并不是一个原子操作,它的执行过程如下:

    1:从主存中读取变量x副本到工作内存;

    2:给x1

    3:将x1后的值写回主存;

    如果另外一个线程b执行x=x-1,执行过程如下:

    1:从主存中读取变量x副本到工作内存;

    2:给x1

    3:将x1后的值写回主存 ;

    那么显然,最终的x的值是不可靠的。假设x现在为10,线程a1,线程b1,从表面上看,似乎最终x还是为10,但是多线程情况下会有这种情况发生:

    1:线程a从主存读取x副本到工作内存,工作内存中x值为10

    2:线程b从主存读取x副本到工作内存,工作内存中x值为10

    3:线程a将工作内存中x1,工作内存中x值为11

    4:线程ax提交主存中,主存中x11

    5:线程b将工作内存中x值减1,工作内存中x值为9

    6:线程bx提交到中主存中,主存中x9


    同样,x有可能为11,如果x是一个银行账户,线程a存款,线程b扣款,显然这样是有严重问题的,要解决这个问题,必须保证线程a和线程b是有序执行的,并且每个线程执行的加1或减1是一个原子操作。看看下面代码:

    public class Account {  
      
        private int balance;  
      
        public Account(int balance) {  
            this.balance = balance;  
        }  
      
        public int getBalance() {  
            return balance;  
        }  
      
        public void add(int num) {  
            balance = balance + num;  
        }  
      
        public void withdraw(int num) {  
            balance = balance - num;  
        }  
      
        public static void main(String[] args) throws InterruptedException {  
            Account account = new Account(1000);  
            Thread a = new Thread(new AddThread(account, 20), "add");  
            Thread b = new Thread(new WithdrawThread(account, 20), "withdraw");  
            a.start();  
            b.start();  
            a.join();  
            b.join();  
            System.out.println(account.getBalance());  
        }  
      
        static class AddThread implements Runnable {  
            Account account;  
            int     amount;  
      
            public AddThread(Account account, int amount) {  
                this.account = account;  
                this.amount = amount;  
            }  
      
            public void run() {  
                for (int i = 0; i < 200000; i++) {  
                    account.add(amount);  
                }  
            }  
        }  
      
        static class WithdrawThread implements Runnable {  
            Account account;  
            int     amount;  
      
            public WithdrawThread(Account account, int amount) {  
                this.account = account;  
                this.amount = amount;  
            }  
      
            public void run() {  
                for (int i = 0; i < 100000; i++) {  
                    account.withdraw(amount);  
                }  
            }  
        }  
    }  

    第一次执行结果为10200,第二次执行结果为1060,每次执行的结果都是不确定的,因为线程的执行顺序是不可预见的。这是java同步产生的根源,synchronized关键字保证了多个线程对于同步块是互斥的,synchronized作为一种同步手段,解决java多线程的执行有序性和内存可见性,而volatile关键字之解决多线程的内存可见性问题。后面将会详细介绍。

     

    synchronized关键字:

    上面说了,javasynchronized关键字做为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量,这一段代码成为互斥区或 临界区,为了保证共享变量的正确性,synchronized标示了临界区。典型的用法如下:

    synchronized(){  

         临界区代码  

    }

    为了保证银行账户的安全,可以操作账户的方法如下:

    public synchronized void add(int num) {  
         balance = balance + num;  
    }  
    public synchronized void withdraw(int num) {  
         balance = balance - num;  
    } 

    刚才不是说了synchronized的用法是这样的吗:

    synchronized(){  

    临界区代码  

    }

    那么对于public synchronized void add(int num)这种情况,意味着什么呢?其实这种情况,锁就是这个方法所在的对象。同理,如果方法是public static synchronized void add(int num),那么锁就是这个方法所在的class

    理论上,每个对象都可以做为锁,但一个对象做为锁时,应该被多个线程共享,这样才显得有意义,在并发环境下,一个没有共享的对象作为锁是没有意义的。假如有这样的代码:

    public class ThreadTest{  
      public void test(){  
         Object lock=new Object();  
         synchronized (lock){  
            //do something  
         }  
      }  
    }

    lock变量作为一个锁存在根本没有意义,因为它根本不是共享对象,每个线程进来都会执行Object lock=new Object();每个线程都有自己的lock,根本不存在锁竞争。

    每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个被线程被唤醒 (notify)后,才会进入到就绪队列,等待cpu的调度。当一开始线程a第一次执行account.add方法时,jvm会检查锁对象account的就绪队列是否已经有线程在等待,如果有则表明account的锁已经被占用了,由于是第一次运行,account的就绪队列为空,所以线程a获得了锁, 执行account.add方法。如果恰好在这个时候,线程b要执行account.withdraw方法,因为线程a已经获得了锁还没有释放,所以线程b要进入account的就绪队列,等到得到锁后才可以执行。

    一个线程执行临界区代码过程如下:

    1:获得同步锁;

    2:清空工作内存;

    3:从主存拷贝变量副本到工作内存;

    4:对这些变量计算;

    5:将变量从工作内存写回到主存;

    6:释放锁;

    可见,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性(也有缺陷哦,性能,死锁都是问题)

     

    生产者/消费者模式(用锁):

    生产者/消费者模式其实是一种很经典的线程同步模型,很多时候,并不是光保证多个线程对某共享资源操作的互斥性就够了,往往多个线程之间都是有协作的。

    假设有这样一种情况,有一个桌子,桌子上面有一个盘子,盘子里只能放一颗鸡蛋,A专门往盘子里放鸡蛋,如果盘子里有鸡蛋,则一直等到盘子里没鸡蛋,B专门从盘子里拿鸡蛋,如果盘子里没鸡蛋,则等待直到盘子里有鸡蛋。其实盘子就是一个互斥区,每次往盘子放鸡蛋应该都是互斥的,A的等待其实就是主动放弃锁,B等待时还要提醒A放鸡蛋。

    如何让线程主动释放锁?

    很简单,调用锁的wait()方法就好。wait方法是从Object来的,所以任意对象都有这个方法。看这个代码片段:

    Object lock=new Object();//声明了一个对象作为锁  
       synchronized (lock) {  
           balance = balance - num;  
           //这里放弃了同步锁,好不容易得到,又放弃了  
           lock.wait();  
    }

    如果一个线程获得了锁lock,进入了同步块,执行lock.wait(),那么这个线程会进入到lock的阻塞队列。如果调用lock.notify()则会通知阻塞队列的某个线程进入就绪队列。


    声明一个盘子,只能放一个鸡蛋:

    import java.util.ArrayList;  
    import java.util.List;  
      
    public class Plate {  
      
        List<Object> eggs = new ArrayList<Object>();  
      
        public synchronized Object getEgg() {  
            while(eggs.size() == 0) {  
                try {  
                    wait();  
                } catch (InterruptedException e) {  
                }  
            }  
      
            Object egg = eggs.get(0);  
            eggs.clear();// 清空盘子  
            notify();// 唤醒阻塞队列的某线程到就绪队列  
            System.out.println("拿到鸡蛋");  
            return egg;  
        }  
      
        public synchronized void putEgg(Object egg) {  
            while(eggs.size() > 0) {  
                try {  
                    wait();  
                } catch (InterruptedException e) {  
                }  
            }  
            eggs.add(egg);// 往盘子里放鸡蛋  
            notify();// 唤醒阻塞队列的某线程到就绪队列  
            System.out.println("放入鸡蛋");  
        }  
          
        static class AddThread extends Thread{  
            private Plate plate;  
            private Object egg=new Object();  
            public AddThread(Plate plate){  
                this.plate=plate;  
            }  
              
            public void run(){  
                for(int i=0;i<5;i++){  
                    plate.putEgg(egg);  
                }  
            }  
        }  
          
        static class GetThread extends Thread{  
            private Plate plate;  
            public GetThread(Plate plate){  
                this.plate=plate;  
            }  
              
            public void run(){  
                for(int i=0;i<5;i++){  
                    plate.getEgg();  
                }  
            }  
        }  
          
        public static void main(String args[]){  
            try {  
                Plate plate=new Plate();  
                Thread add=new Thread(new AddThread(plate));  
                Thread get=new Thread(new GetThread(plate));  
                add.start();  
                get.start();  
                add.join();  
                get.join();  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("测试结束");  
        }  
    }  

    执行结果:

    放入鸡蛋  

    拿到鸡蛋  

    放入鸡蛋  

    拿到鸡蛋  

    放入鸡蛋  

    拿到鸡蛋  

    放入鸡蛋  

    拿到鸡蛋  

    放入鸡蛋  

    拿到鸡蛋  

    测试结束

     

    声明一个Plate对象为plate,被线程A和线程B共享,A专门放鸡蛋,B专门拿鸡蛋。假设

    1:开始,A调用plate.putEgg方法,此时eggs.size()0,因此顺利将鸡蛋放到盘子,还执行了notify()方法,唤醒锁的阻塞队列的线程,此时阻塞队列还没有线程;

    2:又有一个A线程对象调用plate.putEgg方法,此时eggs.size()不为0,调用wait()方法,自己进入了锁对象的阻塞队列;

    3:此时,来了一个B线程对象,调用plate.getEgg方法,eggs.size()不为0,顺利的拿到了一个鸡蛋,还执行了notify()方法,唤 醒锁的阻塞队列的线程,此时阻塞队列有一个A线程对象,唤醒后,它进入到就绪队列,就绪队列也就它一个,因此马上得到锁,开始往盘子里放鸡蛋,此时盘子是 空的,因此放鸡蛋成功;

    4:假设接着来了线程A,就重复2;假设来料线程B,就重复3

    整个过程都保证了放鸡蛋,拿鸡蛋,放鸡蛋,拿鸡蛋。

     

    volatile关键字:

    volatilejava提供的一种同步手段,只不过它是轻量级的同步,为什么这么说,因为volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性。而最彻底的同步要保证有序性和可见性,例如synchronized。任何被volatile修饰的变量,都不拷贝副本到工作内存,任何修改都及时写在主存。因此对于Valatile修饰的变量的修改,所有线程马上就能看到,但是volatile不能保证对变量的修改是有序的。什么意思呢?假如有这样的代码:

    public class VolatileTest{  
      public volatile int a;  
      public void add(int count){  
           a=a+count;  
      }  
    }


    当一个VolatileTest对象被多个线程共享,a的值不一定是正确的,因为a=a+count包含了好几步操作,而此时多个线程的执行是无序的,因为没有任何机制来保证多个线程的执行有序性和原子性。volatile存在的意义是,任何线程对a的修改,都会马上被其他线程读取到,因为直接操作主存,没有线程对工作内存和主存的同步。所以,volatile的使用场景是有限的,在有限的一些情形下可以使用volatile变量替代锁。要使volatile变量提供理想的线程安全,必须同时满足下面两个条件:

    1)对变量的写操作不依赖于当前值;

    2)该变量没有包含在具有其他变量的不变式中;

    volatile只保证了可见性,所以Volatile适合直接赋值的场景,如:

    public class VolatileTest{  
      public volatile int a;  
      public void setA(int a){  
          this.a=a;  
      }  
    }

    在没有volatile声明时,多线程环境下,a的最终值不一定是正确的,因为this.a=a;涉及到给a赋值和将a同步回主存的步骤,这个顺序可能被打乱。如果用volatile声明了,读取主存副本到工作内存和同步a到主存的步骤,相当于是一个原子操作。所以简单来说,volatile适合这种场景:一个变量被多个线程共享,线程直接给这个变量赋值。这是一种很简单的同步场景,这时候使用volatile的开销将会非常小。

     

    原子类:AtomicInteger

    源码:

    /*
     * @(#)AtomicInteger.java	1.11 06/06/15
     *
     * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
     * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     */
    
    package java.util.concurrent.atomic;
    import sun.misc.Unsafe;
    
    /**
     * An {@code int} value that may be updated atomically.  See the
     * {@link java.util.concurrent.atomic} package specification for
     * description of the properties of atomic variables. An
     * {@code AtomicInteger} is used in applications such as atomically
     * incremented counters, and cannot be used as a replacement for an
     * {@link java.lang.Integer}. However, this class does extend
     * {@code Number} to allow uniform access by tools and utilities that
     * deal with numerically-based classes.
     *
     * @since 1.5
     * @author Doug Lea
    */
    public class AtomicInteger extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        // setup to use Unsafe.compareAndSwapInt for updates
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long valueOffset;
    
        static {
          try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
          } catch (Exception ex) { throw new Error(ex); }
        }
    
        private volatile int value;
    
        /**
         * Creates a new AtomicInteger with the given initial value.
         *
         * @param initialValue the initial value
         */
        public AtomicInteger(int initialValue) {
            value = initialValue;
        }
    
        /**
         * Creates a new AtomicInteger with initial value {@code 0}.
         */
        public AtomicInteger() {
        }
    
        /**
         * Gets the current value.
         *
         * @return the current value
         */
        public final int get() {
            return value;
        }
    
        /**
         * Sets to the given value.
         *
         * @param newValue the new value
         */
        public final void set(int newValue) {
            value = newValue;
        }
    
        /**
         * Eventually sets to the given value.
         *
         * @param newValue the new value
         * @since 1.6
         */
        public final void lazySet(int newValue) {
            unsafe.putOrderedInt(this, valueOffset, newValue);
        }
    
        /**
         * Atomically sets to the given value and returns the old value.
         *
         * @param newValue the new value
         * @return the previous value
         */
        public final int getAndSet(int newValue) {
            for (;;) {
                int current = get();
                if (compareAndSet(current, newValue))
                    return current;
            }
        }
    
        /**
         * Atomically sets the value to the given updated value
         * if the current value {@code ==} the expected value.
         *
         * @param expect the expected value
         * @param update the new value
         * @return true if successful. False return indicates that
         * the actual value was not equal to the expected value.
         */
        public final boolean compareAndSet(int expect, int update) {
    	return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    
        /**
         * Atomically sets the value to the given updated value
         * if the current value {@code ==} the expected value.
         *
         * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
         * and does not provide ordering guarantees, so is only rarely an
         * appropriate alternative to {@code compareAndSet}.
         *
         * @param expect the expected value
         * @param update the new value
         * @return true if successful.
         */
        public final boolean weakCompareAndSet(int expect, int update) {
    	return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    
        /**
         * Atomically increments by one the current value.
         *
         * @return the previous value
         */
        public final int getAndIncrement() {
            for (;;) {
                int current = get();
                int next = current + 1;
                if (compareAndSet(current, next))
                    return current;
            }
        }
    
        /**
         * Atomically decrements by one the current value.
         *
         * @return the previous value
         */
        public final int getAndDecrement() {
            for (;;) {
                int current = get();
                int next = current - 1;
                if (compareAndSet(current, next))
                    return current;
            }
        }
    
        /**
         * Atomically adds the given value to the current value.
         *
         * @param delta the value to add
         * @return the previous value
         */
        public final int getAndAdd(int delta) {
            for (;;) {
                int current = get();
                int next = current + delta;
                if (compareAndSet(current, next))
                    return current;
            }
        }
    
        /**
         * Atomically increments by one the current value.
         *
         * @return the updated value
         */
        public final int incrementAndGet() {
            for (;;) {
                int current = get();
                int next = current + 1;
                if (compareAndSet(current, next))
                    return next;
            }
        }
    
        /**
         * Atomically decrements by one the current value.
         *
         * @return the updated value
         */
        public final int decrementAndGet() {
            for (;;) {
                int current = get();
                int next = current - 1;
                if (compareAndSet(current, next))
                    return next;
            }
        }
    
        /**
         * Atomically adds the given value to the current value.
         *
         * @param delta the value to add
         * @return the updated value
         */
        public final int addAndGet(int delta) {
            for (;;) {
                int current = get();
                int next = current + delta;
                if (compareAndSet(current, next))
                    return next;
            }
        }
    
        /**
         * Returns the String representation of the current value.
         * @return the String representation of the current value.
         */
        public String toString() {
            return Integer.toString(get());
        }
    
    
        public int intValue() {
    	return get();
        }
    
        public long longValue() {
    	return (long)get();
        }
    
        public float floatValue() {
    	return (float)get();
        }
    
        public double doubleValue() {
    	return (double)get();
        }
    
    }

    compareAndSet调用Unsafe来实现:

    private static final Unsafe unsafe = Unsafe.getUnsafe();

    compareAndSet方法首先判断当前值是否等于current

    如果当前值 = current ,说明AtomicInteger的值没有被其他线程修改;

    如果当前值 != current,说明AtomicInteger的值被其他线程修改了,这时会再次进入循环重新比较;

     

    java提供的原子操作可以原子更新的基本类型有以下三个:

    1AtomicBoolean

    2AtomicInteger

    3AtomicLong

     

    java提供的原子操作,还可以原子更新以下类型的值:

    1,原子更新数组,Atomic包提供了以下几个类:AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray

    2,原子更新引用类型,也就是更新实体类的值,比如AtomicReference<User>

    AtomicReference:原子更新引用类型的值

    AtomicReferenceFieldUpdater:原子更新引用类型里的字段

    AtomicMarkableReference:原子更新带有标记位的引用类型

    3,原子更新字段值

    AtomicIntegerFieldUpdater:原子更新整形的字段的更新器

    AtomicLongFieldUpdater:原子更新长整形的字段的更新器

    AtomicStampedReference:原子更新带有版本号的引用类型的更新器


    下一篇,未完待续......

    展开全文
  • java--进程和线程

    2019-02-18 16:00:49
    在学习线程之前要先知道什么是进程进程就是正在运行的程序,它是系统资源调度的独立单位,并且一个进程可以执行多个任务,而线程就是程序执行的任务,它是程序使用CPU的基本单位,因此也可以说线程是依赖于进程的...

    进程和线程的概述

    在学习线程之前要先知道什么是进程,进程就是正在运行的程序,它是系统资源调度的独立单位,并且一个进程可以执行多个任务,而线程就是程序执行的任务,它是程序使用CPU的基本单位,因此也可以说线程是依赖于进程的。

    进程

    进程就是正在运行的程序,它是系统资源调度的独立单位,各个进程之间不会相互影响,因为系统给它们分配了不同的空间和资源,它分为单进程和多进程。

    单进程与多进程的概述

    单进程的计算机一次只能做一件事情,而多进程的计算机可以做到一次做不同的事情,比如一边听音乐,一边听打游戏,这两件事情虽然感觉起来是在同时一起进行的,但其实是CPU在做着程序间的高效切换,这才让我们觉得是同时进行的。

    线程

    线程就是程序(进程)执行的任务,它分为单线程和多线程。

    单线程与多线程的概述

    单线程也就是做的事情专一,不会分神去做别的事,也就是程序只有一条执行路径;多线程就是可以分出多条路去做同一件事情,也就是程序有多条执行路径,比如三个伙伴迷路了,大家分别去问路人路线,最后大家在目的地集合,因此多线程的存在,不是提高程序的执行速度,其实是为了提高应用程序的使用率,也可以说程序的执行其实都是在抢CPU的资源,也就是抢CPU的执行权,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权,但这一过程是随机的,不知道哪一个线程会在哪一个时刻占到这个资源,所以线程的执行有随机性。

    Thread类

    想要实现多进程就要继承Thread类,重写run方法,然后调用start方法,这样就可以创建并执行新的线程,直接调用run方法可不是开始执行线程哟,因为run方法是由jvm从线程中调用的,因此不要以为直接调用run方法是在执行线程哟。

    匿名内部类的方式实现线程

    格式:
            new Thread(){代码…}.start();
                        或
            new Thread(new Runnable(){代码…}).start();

    Runnable接口

    Runnable接口也可以实现线程,这种方式扩展性强,可以实现一个接口,还可以再去继承其他类,当然这个也是要重写run方法的,实现该接口后与Thread类一起使用。

    代码演示

    某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票,通过实现Runnable接口实现(模拟网络延迟)。

    public class Ticket implements Runnable{
        //设置票数
        int ticket = 100 ;
        @Override
        public void run() {
            while (true) {
                    if (ticket > 0) {
                        try {
                            Thread.sleep(1000);//模拟网络延迟
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售" + (ticket--) + "张票");
                    }else {
                    //当票不满足条件是退出循环
                        break;
                    }
            }
        }
    }
    public class MyTicket {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
            //把Ticket对象放入Thread中可以起到对象共享,这样数据才会同步,如果变量是静态的可直接new Thread对象,因为静态变量是共享的
            Thread thread1 = new Thread(ticket);
            //设置线程名字
            thread1.setName("窗口1");
    
            Thread thread2 = new Thread(ticket);
            thread2.setName("窗口2");
    
            Thread thread3 = new Thread(ticket);
            thread3.setName("窗口3");
            //开启线程
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }
    

    结果

    窗口1正在出售100张票
    窗口3正在出售99张票
    窗口2正在出售98张票
    窗口2正在出售97张票
    窗口1正在出售96张票
    窗口3正在出售95张票
    窗口3正在出售94张票
    窗口1正在出售93张票
    窗口2正在出售92张票
    窗口1正在出售91张票
    窗口3正在出售90张票
    窗口2正在出售89张票
    窗口1正在出售88张票
    窗口3正在出售87张票
    窗口2正在出售86张票
    窗口2正在出售85张票
    窗口1正在出售84张票
    窗口3正在出售83张票
    窗口1正在出售82张票
    窗口3正在出售81张票
    窗口2正在出售80张票
    窗口2正在出售79张票
    窗口3正在出售78张票
    窗口1正在出售77张票
    窗口2正在出售76张票
    窗口3正在出售75张票
    窗口1正在出售74张票
    窗口2正在出售73张票
    窗口3正在出售72张票
    窗口1正在出售71张票
    窗口3正在出售70张票
    窗口1正在出售69张票
    窗口2正在出售68张票
    窗口1正在出售67张票
    窗口3正在出售66张票
    窗口2正在出售65张票
    窗口1正在出售64张票
    窗口3正在出售63张票
    窗口2正在出售62张票
    窗口1正在出售61张票
    窗口3正在出售60张票
    窗口2正在出售59张票
    窗口1正在出售58张票
    窗口3正在出售57张票
    窗口2正在出售56张票
    窗口1正在出售55张票
    窗口3正在出售54张票
    窗口2正在出售53张票
    窗口3正在出售52张票
    窗口1正在出售51张票
    窗口2正在出售50张票
    窗口1正在出售49张票
    窗口3正在出售48张票
    窗口2正在出售47张票
    窗口3正在出售46张票
    窗口1正在出售45张票
    窗口2正在出售44张票
    窗口1正在出售43张票
    窗口3正在出售42张票
    窗口2正在出售41张票
    窗口3正在出售40张票
    窗口1正在出售39张票
    窗口2正在出售38张票
    窗口3正在出售37张票
    窗口1正在出售36张票
    窗口2正在出售35张票
    窗口2正在出售34张票
    窗口1正在出售33张票
    窗口3正在出售32张票
    窗口2正在出售31张票
    窗口2正在出售30张票
    窗口3正在出售28张票
    窗口1正在出售29张票
    窗口2正在出售27张票
    窗口3正在出售26张票
    窗口1正在出售25张票
    窗口2正在出售24张票
    窗口2正在出售23张票
    窗口3正在出售22张票
    窗口1正在出售21张票
    窗口2正在出售20张票
    窗口3正在出售19张票
    窗口1正在出售18张票
    窗口2正在出售17张票
    窗口3正在出售16张票
    窗口1正在出售15张票
    窗口2正在出售14张票
    窗口2正在出售13张票
    窗口3正在出售12张票
    窗口1正在出售11张票
    窗口2正在出售10张票
    窗口3正在出售9张票
    窗口1正在出售8张票
    窗口2正在出售7张票
    窗口1正在出售6张票
    窗口3正在出售5张票
    窗口1正在出售4张票
    窗口3正在出售3张票
    窗口2正在出售2张票
    窗口2正在出售1张票
    窗口3正在出售0张票
    窗口1正在出售-1张票

    你会发现这里会出现0和-1张票,这是为什么呢?(拿上述结果说明)因为在窗口2线程抢到执行权进来时,会休眠1秒,休眠的这段期间,另一个窗口抢到了执行权,也就是窗口3,这时候窗口3也进来了,然后它也休眠了,这个时候窗口2苏醒啦,它就完成了票减1,票就变为1了,在窗口3还没苏醒时窗口1进来并休眠了,然后窗口3苏醒了,它也进行了减1,票就变为了0,最后窗口1醒来并减1,票就变为-1了,因此出现了以上的结果,这就体现了线程的互斥性;

    上面的结果也可能出现相同票数的窗口,原因是ticket--不具有原子性(原子性也就是式子不是一次计算出结果的,而是分布计算结果的,如:i--,它是先输出i的值,然后在进行i=i-1,同理i++)式子,如:当窗口1休眠时,窗口3进入之后也休眠,这时窗口1苏醒了,进行到输出i的值这一步时,窗口3苏醒了并抢到了执行权,它也进行了输出i,由于上一步还没进行到i-1的步骤,因此窗口3和窗口1输出的值相同,这就是原子性。这些都是在网络延迟中会出现的问题。

    想要解决以上问题(也就是线程安全问题),只让一个线程进入,并阻止另一个线程进入,那么就使用到了synchronize(同步代码块)或者继承Lock(锁)。

    线程安全问题

    线程安全问题遵循这三个规律:是否是多线程;是否有共享数据;是否有多个线程操作共享数据。

    synchronize同步代码块

    同步代码块解决的出现解决了线程的安全问题,但是当线程相当多时,每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率;同步代码块把进入的线程锁住,这样就可以解决之前演示的问题了,这个把线程锁住的锁是内置锁(java中的内置锁是互斥锁),也就意味着只有一个线程能去获得这个锁,另一个线程想要获得这个锁,必须等上一个线程释放锁,因此如果这个线程不释放锁,那么另一个线程会一直等下去。

    格式:
            synchronized(对象){
                需要同步的代码;
            }
    这个对象其实就是一把锁,也可以称之为监视器,监视进程的进出,它是同步代码块保证数据的安全性的一个主要因素
    要注意的是这个对象,要定义为静态成员变量,才能被所有线程共享,不能在里面new对象,这样每把锁都不一样了,这个锁也就没有意义了
     

    代码演示

    以上买票为例,Ticket修改为以下

    public class Ticket implements Runnable{
        //设置票数
        int ticket = 100 ;
        //创建一个锁对象,你可以随便new,锁对象:就是一个任意对象
        Object obj=new Object();
        @Override
        public void run() {
            while (true) {
                synchronized (obj) {
                    //线程一旦进入同步代码块,就会持有锁的对象
                    if (ticket > 0) {
                        try {
                            Thread.sleep(1000);//模拟网络延迟
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售" + (ticket--) + "张票");
                    }else {
                        break;
                    }
                }
            }
        }
    }
    public class MyTicket {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
            Thread thread1 = new Thread(ticket);
            thread1.setName("窗口1");
            Thread thread2 = new Thread(ticket);
            thread2.setName("窗口2");
            Thread thread3 = new Thread(ticket);
            thread3.setName("窗口3");
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }

    结果

    窗口2正在出售100张票
    窗口2正在出售99张票
    窗口2正在出售98张票
    窗口2正在出售97张票
    窗口2正在出售96张票
    窗口2正在出售95张票
    窗口2正在出售94张票
    窗口3正在出售93张票
    窗口3正在出售92张票
    窗口1正在出售91张票
    窗口1正在出售90张票
    窗口3正在出售89张票
    窗口3正在出售88张票
    窗口3正在出售87张票
    窗口3正在出售86张票
    窗口2正在出售85张票
    窗口2正在出售84张票
    窗口2正在出售83张票
    窗口2正在出售82张票
    窗口2正在出售81张票
    窗口2正在出售80张票
    窗口2正在出售79张票
    窗口2正在出售78张票
    窗口2正在出售77张票
    窗口3正在出售76张票
    窗口1正在出售75张票
    窗口3正在出售74张票
    窗口3正在出售73张票
    窗口3正在出售72张票
    窗口3正在出售71张票
    窗口3正在出售70张票
    窗口3正在出售69张票
    窗口3正在出售68张票
    窗口3正在出售67张票
    窗口2正在出售66张票
    窗口2正在出售65张票
    窗口2正在出售64张票
    窗口2正在出售63张票
    窗口2正在出售62张票
    窗口2正在出售61张票
    窗口2正在出售60张票
    窗口2正在出售59张票
    窗口2正在出售58张票
    窗口2正在出售57张票
    窗口2正在出售56张票
    窗口2正在出售55张票
    窗口2正在出售54张票
    窗口2正在出售53张票
    窗口2正在出售52张票
    窗口2正在出售51张票
    窗口2正在出售50张票
    窗口2正在出售49张票
    窗口3正在出售48张票
    窗口1正在出售47张票
    窗口1正在出售46张票
    窗口1正在出售45张票
    窗口3正在出售44张票
    窗口3正在出售43张票
    窗口3正在出售42张票
    窗口2正在出售41张票
    窗口3正在出售40张票
    窗口1正在出售39张票
    窗口3正在出售38张票
    窗口2正在出售37张票
    窗口2正在出售36张票
    窗口3正在出售35张票
    窗口1正在出售34张票
    窗口3正在出售33张票
    窗口3正在出售32张票
    窗口3正在出售31张票
    窗口3正在出售30张票
    窗口3正在出售29张票
    窗口3正在出售28张票
    窗口3正在出售27张票
    窗口3正在出售26张票
    窗口3正在出售25张票
    窗口3正在出售24张票
    窗口2正在出售23张票
    窗口3正在出售22张票
    窗口1正在出售21张票
    窗口3正在出售20张票
    窗口2正在出售19张票
    窗口2正在出售18张票
    窗口3正在出售17张票
    窗口1正在出售16张票
    窗口1正在出售15张票
    窗口3正在出售14张票
    窗口3正在出售13张票
    窗口3正在出售12张票
    窗口3正在出售11张票
    窗口3正在出售10张票
    窗口3正在出售9张票
    窗口3正在出售8张票
    窗口3正在出售7张票
    窗口3正在出售6张票
    窗口2正在出售5张票
    窗口2正在出售4张票
    窗口2正在出售3张票
    窗口3正在出售2张票
    窗口1正在出售1张票

    Lock接口

    用同步代码块我们可以给线程上锁,但是具体在哪里上锁和解锁,我们都不知道,因此为了让我们更加清楚如何加锁和解锁,在JDK5以后提供了Lock接口和它的ReentrantLock子类,这个锁与synchronized不同,需要手动去加锁和解锁。

    Lock类
    void lock() 加锁
    void unlock() 解锁

    代码演示

    以上买票为例,把Ticket改为以下

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Ticket implements Runnable{
        //设置票数
        int ticket = 100 ;
        Lock lock = new ReentrantLock();
        @Override
        public void run() {
    
            while (true) {
                //加锁,进入循环立马上锁,防止另一个线程跟着进入下面的if判断
                lock.lock();
                if (ticket > 0) {
                        try {
                            Thread.sleep(1000);//模拟网络延迟
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售" + (ticket--) + "张票");
                        //减完票后,这个线程的任务就该释放锁了,好让下一个线程执行任务
                        lock.unlock();
                    }else {
                        break;
                    }
               // }
            }
        }
    }
    public class MyTicket {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
            Thread thread1 = new Thread(ticket);
            thread1.setName("窗口1");
            Thread thread2 = new Thread(ticket);
            thread2.setName("窗口2");
            Thread thread3 = new Thread(ticket);
            thread3.setName("窗口3");
            thread1.start();
            thread2.start();
            thread3.start();
        }
    }

    结果

    窗口2正在出售100张票
    窗口2正在出售99张票
    窗口2正在出售98张票
    窗口2正在出售97张票
    窗口2正在出售96张票
    窗口2正在出售95张票
    窗口2正在出售94张票
    窗口3正在出售93张票
    窗口3正在出售92张票
    窗口1正在出售91张票
    窗口1正在出售90张票
    窗口3正在出售89张票
    窗口3正在出售88张票
    窗口3正在出售87张票
    窗口3正在出售86张票
    窗口2正在出售85张票
    窗口2正在出售84张票
    窗口2正在出售83张票
    窗口2正在出售82张票
    窗口2正在出售81张票
    窗口2正在出售80张票
    窗口2正在出售79张票
    窗口2正在出售78张票
    窗口2正在出售77张票
    窗口3正在出售76张票
    窗口1正在出售75张票
    窗口3正在出售74张票
    窗口3正在出售73张票
    窗口3正在出售72张票
    窗口3正在出售71张票
    窗口3正在出售70张票
    窗口3正在出售69张票
    窗口3正在出售68张票
    窗口3正在出售67张票
    窗口2正在出售66张票
    窗口2正在出售65张票
    窗口2正在出售64张票
    窗口2正在出售63张票
    窗口2正在出售62张票
    窗口2正在出售61张票
    窗口2正在出售60张票
    窗口2正在出售59张票
    窗口2正在出售58张票
    窗口2正在出售57张票
    窗口2正在出售56张票
    窗口2正在出售55张票
    窗口2正在出售54张票
    窗口2正在出售53张票
    窗口2正在出售52张票
    窗口2正在出售51张票
    窗口2正在出售50张票
    窗口2正在出售49张票
    窗口3正在出售48张票
    窗口1正在出售47张票
    窗口1正在出售46张票
    窗口1正在出售45张票
    窗口3正在出售44张票
    窗口3正在出售43张票
    窗口3正在出售42张票
    窗口2正在出售41张票
    窗口3正在出售40张票
    窗口1正在出售39张票
    窗口3正在出售38张票
    窗口2正在出售37张票
    窗口2正在出售36张票
    窗口3正在出售35张票
    窗口1正在出售34张票
    窗口3正在出售33张票
    窗口3正在出售32张票
    窗口3正在出售31张票
    窗口3正在出售30张票
    窗口3正在出售29张票
    窗口3正在出售28张票
    窗口3正在出售27张票
    窗口3正在出售26张票
    窗口3正在出售25张票
    窗口3正在出售24张票
    窗口2正在出售23张票
    窗口3正在出售22张票
    窗口1正在出售21张票
    窗口3正在出售20张票
    窗口2正在出售19张票
    窗口2正在出售18张票
    窗口3正在出售17张票
    窗口1正在出售16张票
    窗口1正在出售15张票
    窗口3正在出售14张票
    窗口3正在出售13张票
    窗口3正在出售12张票
    窗口3正在出售11张票
    窗口3正在出售10张票
    窗口3正在出售9张票
    窗口3正在出售8张票
    窗口3正在出售7张票
    窗口3正在出售6张票
    窗口2正在出售5张票
    窗口2正在出售4张票
    窗口2正在出售3张票
    窗口3正在出售2张票
    窗口1正在出售1张票

    死锁问题

    死锁是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象,这个问题和同步代码块的嵌套有关,如果出现了同步嵌套,就容易产生死锁问题。

    代码演示

    两个人只有一把钥匙串 ,如果一个人拿走钥匙取开门,另一个人就需要等待另一个人开门

    //定义两把钥匙,也就是定义锁对象,把它们定义为静态的,可以直接类名调用
    public interface MyLock {
    	
    	public static final Object key1 = new Object() ;
    	public static final Object key2 = new Object() ;
    
    }
    //继承Thread,重写run方法
    public class Demo extends Thread {
        //定义一个布尔类型来,判断是谁先拿锁,true是1先拿锁,反之是2
        boolean flag;
    
        public Demo(boolean flag){
            this.flag=flag;
        }
        @Override
        public void run() {
            if(flag){
                //嵌套同步代码块
                synchronized (MyLock.key1){
                    System.out.println("门开了1");
                    synchronized (MyLock.key2){
                        System.out.println("门开了2");
                    }
                }
            }else {
                synchronized (MyLock.key2){
                    System.out.println("门开了2");
                    synchronized (MyLock.key1){
                        System.out.println("门开了1");
                    }
                }
            }
    
        }
    }
    public class DemoTest {
        public static void main(String[] args) {
            Demo demo1 = new Demo(true);
            Demo demo2 = new Demo(false);
            demo1.start();
            demo2.start();
        }
    }
    

    结果

    门开了2
    门开了1

    当是true时,由于1先拿了钥匙,还没释放,2就拿不到钥匙,因此就会出现一直等待的现象,这就是死锁。

    内存可见性问题

    Java内存模型规定了所有的变量都存储在主内存中,每条线程中还有自己的工作内存,工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来), 线程对变量的所有操作(读取,赋值)都必须在工作内存中进行,不同线程之间也无法直接访问对方工作内存中的变量,它们间变量值的传递均需要通过主内存来完成。对于解决该问题,Java提供了volatile关键字来,该关键字保证了内存可见性。

    代码演示

    可见性问题

    public class Volatile implements Runnable {
        //定义一个布尔类型,用修改布尔值看这一过程
        private boolean b=false;
        public boolean isB() {
            return b;
        }
    
        public void setB(boolean b) {
            this.b = b;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(50);//模拟网络延迟
            } catch (InterruptedException e) {
    
            }
            //把修改b的值
            b=true;
            //输出b的值
            System.out.println("b="+isB());
        }
    public class VolatileTest {
        public static void main(String[] args) {
            Volatile v = new Volatile();
            Thread th = new Thread(v);
            th.start(); 
            while(true){
            //判断v是否修改成功,修改成功就输出进来啦
                if(v.isB()){
                    System.out.println("进来啦");
                    break;
                }
            }
        }
    }

    结果

    b=true

    上面输出的结果只有修改后的值,并没有输出进来啦这句话,是因为普通修改的值,不会马上就修改到主存中,并且各个线程之间的工作内存是不会互相干扰的,是个独立的存在,它们间变量值的传递均需要通过主内存来完成,因此想要想把修改的值立即写入主存的话就需要volatile这个轻量级的锁(比较省资源);另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中,因此可以保证可见性。

    修改如下:

    public class Volatile implements Runnable {
    //volatile 关键字,可以使修改的值,立即写入主存中
        private volatile boolean b=false;
        public boolean isB() {
            return b;
        }
    
        public void setB(boolean b) {
            this.b = b;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
    
            }
            b=true;
            System.out.println("b="+isB());
        }
    }

    结果

    b=true
    进来啦
    //这个结果的顺序是随机的,因为线程具有随机性

     

    线程池

    程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互,而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池,因为线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,但从JDK5开始,Java内置支持线程池。

    线程池产生的方法
    public static ExecutorService newCachedThreadPool() 根据任务的数量来创建线程
    public static ExecutorService newFixedThreadPool(int nThreads) 固定初始化几个线程
    public static ExecutorService newSingleThreadExecutor() 初始化一个线程的线程池

    代码演示

    1、

    public class MyDemo implements Runnable{
        @Override
        public void run() {
            //通过查看线程名字,看一共有多少线程在执行任务
            System.out.println(Thread.currentThread().getName()+"正在执行程序");
        }
    }
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class DemoTest {
        public static void main(String[] args) {
            //创建一个线程池,里面有两个线程,里面的2就带表线程数,可以随便写
            ExecutorService pool = Executors.newFixedThreadPool(2);
            //创建一个Runnable对象
            MyDemo myDemo = new MyDemo();
            //提交一个 Runnable 任务用于执行
            pool.submit(myDemo);
            pool.submit(myDemo);
            pool.submit(myDemo);
            pool.submit(myDemo);
            //关闭线程池
            pool.shutdown();
        }
    }

    结果

    pool-1-thread-2正在执行程序
    pool-1-thread-1正在执行程序
    pool-1-thread-2正在执行程序
    pool-1-thread-2正在执行程序
    

    从结果你可以看到虽然你提交了四个Runnable对象,但是始终只有两个线程在执行任务,这就是线程池的好处,可以合理的利用线程。

    2、累加操作

    public class MyCallable implements Callable<Integer> {
        int len;
        //用来获取需要累加的数的长度
        public MyCallable(int i) {
            len=i;
        }
    
        @Override
        public Integer call() throws Exception {
            //做累加操作
            int sum=0;
            for (int i = 1; i <= len; i++) {
                sum+=i;
            }
            return sum;
        }
    }
    public class MyTest2 {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //获取一个线程对象的线程池
            //里面的核心线程数和线程数都是1,并且工作队列使用的是无界队列。由于是单线程工作,每次只能处理一个任务,所以后面所有的任务都被阻塞在工作队列中,只能一个个任务执行。
            ExecutorService service = Executors.newSingleThreadExecutor();
            Future<Integer> submit = service.submit(new MyCallable(10));
            Future<Integer> submit2 = service.submit(new MyCallable(100));
            Future<Integer> submit3 = service.submit(new MyCallable(1000));
            System.out.println(submit.get());
            System.out.println(submit2.get());
            System.out.println(submit3.get());
            service.shutdown();
        }
    }

    结果

    55
    5050
    500500

     

    定时器

    定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行,在Java中,可以通过Timer和TimerTask类来实现定义调度的功能。

    Timer类

    Timer类
    public Timer()

    默认的构造方法

    public void schedule(TimerTask task, long delay) 在指定的延迟后执行指定的任务
    public void schedule(TimerTask task,long delay,long period) 计划重复固定延迟执行指定的任务,在指定的延迟后开始
    public void schedule(TimerTask task,  Date time) 在指定的时间计划指定的任务
    public void schedule(TimerTask task,  Date firstTime, long period) 计划重复固定延迟执行指定的任务,在指定的开始时间

     

    TimerTask类

    TimerTask类
    public abstract void run() 定时器任务执行的动作
    public boolean cancel() 取消此定时器任务

    代码演示

    1、输出爆炸啦

    import java.util.Timer;
    import java.util.TimerTask;
    
    //继承TimerTask,需要重新rum方法
    public class Time extends TimerTask {
        @Override
        public void run() {
            System.out.println("爆炸啦");
        }
    }
    import java.util.Timer;
    
    public class TimeTest {
        public static void main(String[] args) {
            //new一个Timer对象,用来调方法
            Timer timer = new Timer();
            //调用Timer对象的方法schedule,第一个参数必须是TimerTask对象,Time继承了它因此也是这个对象,第二个参数表示在2秒后运行run方法,这个参数只有在第一次使用run方法,最后一个参数是每隔1秒,运行一次run方法
            timer.schedule(new Time(),2000,1000);
        }
    }

    这个结果是,不停的输出爆炸啦,要想停掉的话,可以加入cancel()方法,在run方法最后加入这个话,结果会输出一个爆炸啦,因为执行第一次完后就执行到这一语句,定时器就取消了,如下。

    2、

    public class Time extends TimerTask {
        //定义一个Timer对象,到时候可以用它来调用cancel方法
        Timer time;
        //通过构造器给Timer对象赋值
        public Time(Timer time){
            this.time=time;
        }
        @Override
        public void run() {
            System.out.println("爆炸啦");
            //取消定时器
            time.cancel();
        }
    }
    public class TimeTest {
        public static void main(String[] args) {
            Timer timer = new Timer();
            timer.schedule(new Time(timer),2000,1000);
        }
    }

    结果

    爆炸啦

     

    展开全文
  • 如何查看java进程

    2019-08-17 09:32:32
    jps -l (显示java进程的Id和软件名称) jps -lmv(显示java进程的Id和软件名称;显示启动main输入参数;虚拟机参数) 二、Windows篇 jps jps -l(显示java进程的Id和软件路径及名称) ...

    一、Linux篇
    方法一

    ps -ef|grep java

    方法二

    jps -l (显示java进程的Id和软件名称)
    jps -lmv(显示java进程的Id和软件名称;显示启动main输入参数;虚拟机参数)

     

    二、Windows篇

    jps
    jps -l(显示java进程的Id和软件路径及名称)
    展开全文
  • 最近收到邮件报警,说内存使作率...2、从上图可以看到PID:916的java进程占用内存较大。定位线程问题(通过命令查看PID 为25894 进程的线程情况),命令:# ps p 916 -L -o pcpu,pmem,pid,tid,time,tname,cmd ...

    最近收到邮件报警,说内存使作率达到84%。如下图:

    解决方法:

    A:可能是代码原因导致的问题:

    1、使用命令:top 查看当前进程的状态

    2、从上图可以看到PID:916的java进程占用内存较大。定位线程问题(通过命令查看PID 为25894 进程的线程情况),命令:# ps p 916 -L -o pcpu,pmem,pid,tid,time,tname,cmd

     

     由此可以看到这PID:916的进程产生了很多线程。接下来就可以通过jstack查看内存使用的堆栈。

    3、查看内存使用的堆栈:在这里我们挑选了TID=934的线程进行分析,首先需要将934这个id转换为16进制。需输入如下命令,

     printf "%x\n" 9731

     

    4、将PID为916的堆栈信息打印到jstack.log中,命令:jstack -l 916 > jstack.log

     

    5、

     查看堆栈信息文件,命令:vim jstack.log

       在进行搜索TID为2603的相关信息。如图:

    6、分析

       可以看到这个线程状态为:RUNNABLE。是正在运行状态的

        另外其它的大部分线程状态为:WAITING。通过查看文件分析 看到大量 Java Thread State。

       说明它在等待另一个条件的发生,来把自己唤醒,或者干脆它是调用了 sleep(N)。

       此时线程状态大致为以下几种:

       java.lang.Thread.State: WAITING (parking):一直等那个条件发生;

       java.lang.Thread.State: TIMED_WAITING (parking或sleeping):定时的,那个条件不到来,也将定时唤醒自己。

     

    7.代码优化:将文件发送给开发。优化下线程

    B:可能是其他原因导致的问题:

    1、使用ps命令:ps -ef | grep java | grep -v grep

    查看当前java进程列表

    root       834     1  0 May13 ?        00:30:09 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root      1294     1  3 May13 ?        14:41:25 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root      2085     1  0 Mar05 ?        01:57:08 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root     12808     1  0 Mar08 ?        01:16:03 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root     19392     1  0 May09 ?        00:36:19 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root     19838     1  1 May09 ?        05:32:17 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root     21543     1  0 May27 ?        00:22:03 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start
    root     22750     1  5 May27 ?        02:28:41 /usr/lib/jvm/java/bin/java -Djava.util.logging.config.file=/data/apache-tomcat-9.0.13/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /data/apache-tomcat-9.0.13/bin/bootstrap.jar:/data/apache-tomcat-9.0.13/bin/tomcat-juli.jar -Dcatalina.base=/data/apache-tomcat-9.0.13 -Dcatalina.home=/data/apache-tomcat-9.0.13 -Djava.io.tmpdir=/data/apache-tomcat-9.0.13/temp org.apache.catalina.startup.Bootstrap start

    由上图所示,可以看到java进程是Tomcat的启动进程,开启多个Tomcat启动进程,并且是同一个端口。由此,可以判断,是因为关闭Tomcat服务时,java进程没有自动关闭,导致内存没有释放。

    2、使用lsof命令:lsof | grep java |grep -v grep

    查看当前进程的运行状态

    java        834    root  cwd       DIR              252,1      4096     393217 /root
    java        834    root  rtd       DIR              252,1      4096          2 /
    java        834    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java        834    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java        834    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java        834    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java        834    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java        834    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java        834    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java        834    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java        834    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java        834    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    ....................
    
    java       1294    root  cwd       DIR              252,1      4096     393217 /root
    java       1294    root  rtd       DIR              252,1      4096          2 /
    java       1294    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java       1294    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java       1294    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java       1294    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java       1294    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java       1294    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java       1294    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java       1294    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java       1294    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java       1294    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java       1294    root  mem       REG              252,1     11920     131997 /var/cache/fontconfig/beeeeb3dfe132a8a0633a017c99ce0c0-le64.cache-3
    java       1294    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java       1294    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java       1294    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java       1294    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    java       1294    root  mem       REG              252,1     18720     655370 /lib64/libplc4.so
    java       1294    root  mem       REG              252,1     14528     655377 /lib64/libplds4.so
    java       1294    root  mem       REG              252,1    191928     266783 /usr/lib64/libnssutil3.so
    java       1294    root  mem       REG              252,1   1337168     268947 /usr/lib64/libnss3.so
    ............
    
    java       2085    root  cwd       DIR             252,17      4096    2621998 /data/apache-tomcat-9.0.13/bin
    java       2085    root  rtd       DIR              252,1      4096          2 /
    java       2085    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java       2085    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java       2085    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java       2085    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java       2085    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java       2085    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java       2085    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java       2085    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    java       2085    root  mem       REG              252,1     18720     655370 /lib64/libplc4.so
    java       2085    root  mem       REG              252,1     14528     655377 /lib64/libplds4.so
    java       2085    root  mem       REG              252,1    191928     266783 /usr/lib64/libnssutil3.so
    java       2085    root  mem       REG              252,1   1337168     268947 /usr/lib64/libnss3.so
    java       2085    root  mem       REG              252,1    185368     266802 /usr/lib64/libsmime3.so
    java       2085    root  mem       REG              252,1    336472     269139 /usr/lib64/libssl3.so
    java       2085    root  mem       REG              252,1     45720     792689 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libsunec.so
    java       2085    root  mem       REG              252,1     36088     792682 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libmanagement.so
    java       2085    root  mem       REG              252,1     98280     792684 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libnet.so
    java       2085    root  mem       REG              252,1     73416     792685 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libnio.so
    java       2085    root  mem       REG             252,17     34918    2622001 /data/apache-tomcat-9.0.13/bin/bootstrap.jar
    java       2085    root  mem       REG              252,1  73280094     792748 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/rt.jar
    java       2085    root  mem       REG              252,1    298029     792717 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/ext/sunjce_provider.jar
    ............
    
    java      12808    root  cwd       DIR              252,1      4096     393217 /root
    java      12808    root  rtd       DIR              252,1      4096          2 /
    java      12808    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java      12808    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java      12808    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java      12808    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java      12808    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java      12808    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java      12808    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    java      12808    root  mem       REG              252,1     18720     655370 /lib64/libplc4.so
    java      12808    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java      12808    root  mem       REG              252,1     14528     655377 /lib64/libplds4.so
    java      12808    root  mem       REG              252,1    191928     266783 /usr/lib64/libnssutil3.so
    java      12808    root  mem       REG              252,1   1337168     268947 /usr/lib64/libnss3.so
    java      12808    root  mem       REG              252,1    185368     266802 /usr/lib64/libsmime3.so
    java      12808    root  mem       REG              252,1    336472     269139 /usr/lib64/libssl3.so
    java      12808    root  mem       REG              252,1     45720     792689 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libsunec.so
    java      12808    root  mem       REG              252,1     36088     792682 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libmanagement.so
    java      12808    root  mem       REG              252,1     98280     792684 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libnet.so
    java      12808    root  mem       REG              252,1     73416     792685 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libnio.so
    ..........
    
    java      19392    root  cwd       DIR              252,1      4096     393217 /root
    java      19392    root  rtd       DIR              252,1      4096          2 /
    java      19392    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java      19392    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java      19392    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java      19392    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java      19392    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java      19392    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java      19392    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java      19392    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java      19392    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java      19392    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java      19392    root  mem       REG              252,1     11920     131997 /var/cache/fontconfig/beeeeb3dfe132a8a0633a017c99ce0c0-le64.cache-3
    java      19392    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java      19392    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java      19392    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java      19392    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    java      19392    root  mem       REG              252,1     18720     655370 /lib64/libplc4.so
    java      19392    root  mem       REG              252,1     14528     655377 /lib64/libplds4.so
    java      19392    root  mem       REG              252,1    191928     266783 /usr/lib64/libnssutil3.so
    ...........
    
    java      19838    root  cwd       DIR              252,1      4096     393217 /root
    java      19838    root  rtd       DIR              252,1      4096          2 /
    java      19838    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java      19838    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java      19838    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java      19838    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java      19838    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java      19838    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java      19838    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java      19838    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java      19838    root  mem       REG              252,1     11920     131997 /var/cache/fontconfig/beeeeb3dfe132a8a0633a017c99ce0c0-le64.cache-3
    java      19838    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java      19838    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java      19838    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java      19838    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java      19838    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java      19838    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    java      19838    root  mem       REG              252,1     18720     655370 /lib64/libplc4.so
    java      19838    root  mem       REG              252,1     14528     655377 /lib64/libplds4.so
    .........
    
    java      21543    root  cwd       DIR              252,1      4096     393217 /root
    java      21543    root  rtd       DIR              252,1      4096          2 /
    java      21543    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java      21543    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java      21543    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java      21543    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java      21543    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java      21543    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java      21543    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java      21543    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java      21543    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java      21543    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java      21543    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java      21543    root  mem       REG              252,1     11920     131997 /var/cache/fontconfig/beeeeb3dfe132a8a0633a017c99ce0c0-le64.cache-3
    java      21543    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java      21543    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    java      21543    root  mem       REG              252,1     18720     655370 /lib64/libplc4.so
    java      21543    root  mem       REG              252,1     14528     655377 /lib64/libplds4.so
    java      21543    root  mem       REG              252,1    191928     266783 /usr/lib64/libnssutil3.so
    ........
    
    java      22750    root  cwd       DIR              252,1      4096     393217 /root
    java      22750    root  rtd       DIR              252,1      4096          2 /
    java      22750    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java      22750    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java      22750    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java      22750    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java      22750    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java      22750    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java      22750    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java      22750    root  mem       REG              252,1    111440     656920 /lib64/libresolv-2.12.so
    java      22750    root  mem       REG              252,1     27896     655389 /lib64/libnss_dns-2.12.so
    java      22750    root  mem       REG              252,1     11920     131997 /var/cache/fontconfig/beeeeb3dfe132a8a0633a017c99ce0c0-le64.cache-3
    java      22750    root  mem       REG              252,1   3203275     792699 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/charsets.jar
    java      22750    root  mem       REG              252,1   3509512     792747 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/resources.jar
    java      22750    root  mem       REG              252,1    477712     655369 /lib64/libfreeblpriv3.so
    java      22750    root  mem       REG              252,1    248720     655363 /lib64/libnspr4.so
    ........
    
    java      29458    root  cwd       DIR              252,1      4096     393217 /root
    java      29458    root  rtd       DIR              252,1      4096          2 /
    java      29458    root  txt       REG              252,1      5128     917742 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/bin/java
    java      29458    root  mem       REG              252,1  99174448     269459 /usr/lib/locale/locale-archive
    java      29458    root  mem       REG              252,1    262896     269147 /usr/lib64/libjpeg.so.62.0.0
    java      29458    root  mem       REG              252,1     41400     792676 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libjavajpeg.so
    java      29458    root  mem       REG              252,1    644072     266782 /usr/lib64/libfreetype.so.6.3.22
    java      29458    root  mem       REG              252,1    349032     792667 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libfontmanager.so
    java      29458    root  mem       REG              252,1     29072     792665 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt_headless.so
    java      29458    root  mem       REG              252,1    715224     792664 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el6_10.x86_64/jre/lib/amd64/libawt.so
    java      29458    root  mem       REG              252,1     11920     131997 /var/cache/fontconfig/beeeeb3dfe132a8a0633a017c99ce0c0-le64.cache-3
    ............
    java      29458    root  235u     IPv4           34489969       0t0        TCP localhost:57037->localhost:mysql (ESTABLISHED)
    java      29458    root  236u     IPv4           34489971       0t0        TCP localhost:57036->localhost:mysql (ESTABLISHED)
    java      29458    root  237u     IPv4           34489970       0t0        TCP localhost:57040->localhost:mysql (ESTABLISHED)
    java      29458    root  238u     IPv4           34489982       0t0        TCP localhost:57042->localhost:mysql (ESTABLISHED)
    java      29458    root  239u     IPv4           34489983       0t0        TCP localhost:57043->localhost:mysql (ESTABLISHED)
    java      29458    root  240u     IPv4           34489984       0t0        TCP localhost:57046->localhost:mysql (ESTABLISHED)

    通过上图所示:正常运行的Tomcat状态应为PID:29458的java进程

    3、杀掉其他的java的进程

    kill -9 PID

    4、然后查看主机监控,果然内存使用率下降,网站运行正常

     

    转载于:https://www.cnblogs.com/eeexu123/p/10913389.html

    展开全文
  • 查看Java进程

    2019-11-06 23:57:19
    Linux 方法一: ...jps -l (显示Java进程的Id和软件名称) jps -lmv(显示Java的进程Id和软件名称;显示启动main输入参数;虚拟机参数) Windows jps jps -l(显示Java进程的Id和软件路径及名称) ...
  • jps -lvm 用于查看当前机器上运行的java进程。 可以看到所有运行的java进程都列出来了 top -Hp pid可以查看某个进程的线程信息 -H 显示线程信息,-p指定pid 如果想查看某个进程下的线程的堆栈信息的话可以...
  • JAVA进程空间

    2016-10-05 13:05:29
    http://www.ibm.com/developerworks/cn/java/j-nativememory-linux/ http://blog.csdn.net/chaofanwei/article/details/19418753 http://www.open-open.com/lib/view/open1431570358826.html http://vani
  • 面试官赶时间,导致我的语速也快了起来,其中有个问题没答上,那就是Linux下查看java进程的命令。 回来做个记录,以防还有公司问到(之前工作上遇到Linux还是太少了(;´д`)ゞ,服)。 Linux下查看和停止所有...
  • 本文转自:linux下如何批量杀JAVA进程或某个进程方法 linux下如何批量杀JAVA进程或某个进程方法 在工作中经常需要停止JAVA进程,停止时间也比较长,那么有时候因为一些情况,需要把 linux 下JAVA所有进程 kill 掉...
  • 首先是获取当前Java运行的Java进程ID,这个是网上常见的,也就是Java程序自身将进程ID打印出来:package com.test;import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean;...
  • 1. Linux下查看和停止所有java进程 在Linux下查看所有java进程命令:ps -ef | grep java 停止所有java进程命令:pkill - 9 java 停止特定java进程命令:kill -9 java进程序号
  • java 进程通信代码

    2018-08-03 13:01:11
    本人写了一个java进程通信的工具jar,方便大家简单的使用java进程通信。 开启守护进程,获取消息: package com.test; import org.msun.process.ProcessMonitor; import org.msun.process.ProcessMonitor....
  • Linux 下查看java进程

    2018-11-29 16:37:02
    Linux下查看和停止所有java进程 1.ps -ef | grep java 在Linux下查看所有java进程命令:ps -ef | grep java 停止特定java进程命令:kill -9 java进程序号 停止所有java进程命令:pkill - 9 java 2.jps jps -l -v ...
  • kill所有java进程

    2018-08-21 10:40:23
    ps -ef | grep java | grep -v grep |awk '{print $2}' | xargs -p kill -9 ...Aix 通过shell脚本kill杀指定进程,比如杀所有java进程   ----脚本杀进程------------------------------- cat ./killWAS...
  • 如图可以看到java的进程内存使用率较高,java进程的内存使用率达到了70%+ 2.定位线程问题(通过命令查看9718进程的线程情况),命令:ps p 9718 -L -o pcpu,pmem,pid,tid,time,tname,cmd  由此可以看到这PID...
  •  我们一般启动的jar 在任务管理器中查看进程都是javaw.exe ,无法用命令来 kill,所以我们得给自己的java 进程设置个新 title  一:第一种方法  1: 首先将C:\Program Files\Java\jdk1.8.0_45\bin目录下的javaw....
  • 转载自 jps命令:查看Java进程等详细信息jps是java自带的查看java进程的命令,通过这个命令可以查看当前系统所有运行中的java进程、java包名、jar包名及JVM参数等。jps -help 可以查看命令用法。-q: 只显示VM 标示...
  • 本着在win上监控远程多台liunx 系统中的 java进程想法,做的一系列配置 要实现远程监控Java进程,必须在远程主机(运行Java程序的主机)上跑一个jstatd进程,这个进程相当于一个agent,用来收集远程主机上的JVM...
  • windows关闭java进程

    2017-07-10 15:29:57
    windows关闭java进程 taskkill /F /IM java.exe
1 2 3 4 5 ... 20
收藏数 574,819
精华内容 229,927
关键字:

java进程