Saturday, October 3, 2015

JDK 9'da Process API'deki Yenilikler

JDK 9'un çıkmasına daha henüz çok var, yaklaşık bir yıl:
2015/12/10Feature Complete
2016/02/04All Tests Run
2016/02/25Rampdown Start
2016/04/21Zero Bug Bounce
2016/06/16Rampdown Phase 2
2016/07/21Final Release Candidate
2016/09/22General Availability
JDK 9'daki yenilikler yine JDK 8'de olduğu gibi Oracle firmasına önerilen ve kabul edilen JEP (JDK Enhancement Proposal) üzerinden gerçekleşiyor. Şu ana kadar kabul edilen JEP'ler aşağıda listelenmiştir:
102: Process API Updates
110: HTTP 2 Client
143: Improve Contended Locking
158: Unified JVM Logging
165: Compiler Control
193: Variable Handles
197: Segmented Code Cache
199: Smart Java Compilation, Phase Two
201: Modular Source Code
211: Elide Deprecation Warnings on Import Statements
212: Resolve Lint and Doclint Warnings
213: Milling Project Coin
214: Remove GC Combinations Deprecated in JDK 8
215: Tiered Attribution for javac
216: Process Import Statements Correctly
217: Annotations Pipeline 2.0
219: Datagram Transport Layer Security (DTLS)
220: Modular Run-Time Images
221: Simplified Doclet API
222: jshell: The Java Shell (Read-Eval-Print Loop)
223: New Version-String Scheme
224: HTML5 Javadoc
225: Javadoc Search
226: UTF-8 Property Files
227: Unicode 7.0
228: Add More Diagnostic Commands
229: Create PKCS12 Keystores by Default
230: Microbenchmark Suite
231: Remove Launch-Time JRE Version Selection
232: Improve Secure Application Performance
233: Generate Run-Time Compiler Tests Automatically
235: Test Class-File Attributes Generated by javac
236: Parser API for Nashorn
237: Linux/AArch64 Port
238: Multi-Release JAR Files
240: Remove the JVM TI hprof Agent
241: Remove the jhat Tool
243: Java-Level JVM Compiler Interface
244: TLS Application-Layer Protocol Negotiation Extension
245: Validate JVM Command-Line Flag Arguments
246: Leverage CPU Instructions for GHASH and RSA
247: Compile for Older Platform Versions
248: Make G1 the Default Garbage Collector
249: OCSP Stapling for TLS
250: Store Interned Strings in CDS Archives
251: Multi-Resolution Images
252: Use CLDR Locale Data by Default
253: Prepare JavaFX UI Controls & CSS APIs for Modularization
254: Compact Strings
255: Merge Selected Xerces 2.11.0 Updates into JAXP
256: BeanInfo Annotations
257: Update JavaFX/Media to Newer Version of GStreamer
258: HarfBuzz Font-Layout Engine
Bu yazıda listenin ilk sırasındaki Process API'ye getirilmesi planlanan yeniliklere göz atacağız. İşletim sisteminde çalışan uygulamalar proses olarak adlandırılır. JDK, 1.0 sürümünden itibaren proseslerle çalışmak için bize java.lang.Process soyutlaması sunmuş olsa da, prosesin kimlik bilgisini (PID, Process ID) elde etmek gibi basit bir işlem için bile içinde bir çözüm bulamıyoruz. Çalışan uygulamanın PID değerini, çok dolaylı bir yoldan, sorunlu bir şekilde elde etmek durumunda kalırız:
package com.example.process;

import java.lang.management.ManagementFactory;

/**
 *   @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class GetPID {

   private static final int PID = 0;
   private static final int HOST = 1;

   public static void main(String[] args) {
      String name = ManagementFactory.getRuntimeMXBean().getName();
      String[] parts = name.split("@");
      int pid = Integer.parseInt(parts[PID]);
      String host = parts[HOST];
      System.out.println("PID : " + pid);
      System.out.println("Host: " + host);
   }
}
Java 9'da ProcessHandle sınıfı ile tanışıyoruz. Bu sınıfı kullanarak, örneğin, çalışan uygulamanın PID değerine basit ve sorunsuz bir şekilde ulaşabiliriz:
package com.example.java9;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class GetPID {

    public static void main(String[] args) {
        System.err.println("PID: " + ProcessHandle.current().getPid());
    }

}
ProcessHandle sınıfı kullanılarak, işletim sistemindeki tüm proses bilgilerine ulaşılabilinir. Aşağıda bu yeni sınıf yardımı ile neler yapabileceğimize bir bakalım. Java 9 API'leri elbette Java 8 ile gelen tüm yeniliklerden yararlanıyor: Stream API, Lambda ifadeleri, MapReduce çatısı, Optional, CompletableFuture, Time API ve diğerleri.
  • İşletim sisteminde çalışan proseslerin sayısı
package com.example.java9;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class PrintNumberOfProcesses {

    public static void main(String[] args) {
        long numberOfProcesses = ProcessHandle.allProcesses().count();
        System.out.println("Number of processes: " + numberOfProcesses);
    }
}
  • İşletim sisteminde çalışan prosesleri yaratan komutların listesi
package com.example.java9;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class ListAllCommands {

 public static void main(String[] args) {
    Consumer<String> printCommand
         = command -> {
             Path path = Paths.get(command);
             System.out.println(path.getFileName());
         };
    ProcessHandle.allProcesses()
           .filter( p -> p.info().command().isPresent() )
           .map( p -> process.info().command().get() )
           .distinct()
           .sorted()
           .forEach(printCommand);
 }
}
Örnek ekran çıktısı:
acrotray.exe
chrome.exe
vmware-tray.exe
ETDCtrl.exe
ipoint.exe
itype.exe
Nimi Places.exe
RAVBg64.exe
RAVCpl64.exe
livecomm.exe
WWAHost.exe
GWX.exe
RuntimeBroker.exe
SettingSyncHost.exe
SkyDrive.exe
conhost.exe
hkcmd.exe
igfxpers.exe
igfxsrvc.exe
mspaint.exe
rundll32.exe
taskhostex.exe
explorer.exe
splwow64.exe
notepad++.exe
java.exe
netbeans64.exe
TSVNCache.exe
TOTALCMD64.EXE
VBoxSVC.exe
VirtualBox.exe
  • İşletim sistemindeki tüm proseslerin listesi
package com.example.java9;

import java.util.function.Consumer;
import static java.lang.ProcessHandle.Info;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class ListAllProcesses {

    public static void main(String[] args) {
        DateTimeFormatter formatter
                = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss")
                .withZone(ZoneId.systemDefault());
        Consumer<String> printUser = user -> {
            System.out.println("User: " + user);
        };
        Consumer<String> printCmd = cmd -> {
            System.out.println("Command: " + cmd);
        };
        Consumer<String> printCmdLine = cmdln -> {
            System.out.println("Command line: " + cmdln);
        };
        Consumer<String[]> printArgs = arguments -> {
            System.out.println("Arguments: " + Arrays.toString(arguments));
        };
        Consumer<Instant> printInstant = inst -> {
            System.out.println("Start time: " + formatter.format(inst));
        };
        Consumer<Duration> printCpu = duration -> {
            System.out.println("CPU time (millisec): " + duration.toMillis());
        };
        Consumer<Info> printInfo
                = info -> {
                    info.user().ifPresent(printUser);
                    info.command().ifPresent(printCmd);
                    info.commandLine().ifPresent(printCmdLine);
                    info.arguments().ifPresent(printArgs);
                    info.startInstant().ifPresent(printInstant);
                    info.totalCpuDuration().ifPresent(printCpu);
                    System.out.println();
                };

        ProcessHandle.allProcesses()
                .filter(p -> p.isAlive())
                .map(p -> p.info())
                .forEach(printInfo);
    }
}
Uygulamanın örnek ekran çıktısı:
run:
User: OMEGACW\bkurt
Command: C:\Program Files\Microsoft Mouse and Keyboard Center\itype.exe
Start time: 2015-09-28-00:40:25
CPU time (millisec): 77953

User: OMEGACW\bkurt
Command: C:\Program Files\Microsoft Mouse and Keyboard Center\ipoint.exe
Start time: 2015-09-28-00:40:25
CPU time (millisec): 166984

User: OMEGACW\bkurt
Command: C:\Windows\System32\taskhostex.exe
Start time: 2015-09-28-00:40:25
CPU time (millisec): 9265

User: OMEGACW\bkurt
Command: C:\Windows\explorer.exe
Start time: 2015-09-28-00:40:25
CPU time (millisec): 640453

User: OMEGACW\bkurt
Command: C:\Windows\System32\GWX\GWX.exe
Start time: 2015-09-28-00:40:41
CPU time (millisec): 2437

User: OMEGACW\bkurt
Command: C:\Windows\System32\SettingSyncHost.exe
Start time: 2015-09-28-00:41:25
CPU time (millisec): 55937

User: OMEGACW\bkurt
Command: C:\Windows\System32\SkyDrive.exe
Start time: 2015-09-28-00:41:37
CPU time (millisec): 4796

User: OMEGACW\bkurt
Command: C:\opt64\tortoisesvn\bin\TSVNCache.exe
Start time: 2015-09-28-00:41:42
CPU time (millisec): 1562

User: OMEGACW\bkurt
Command: C:\Windows\System32\igfxsrvc.exe
Start time: 2015-09-28-00:41:50
CPU time (millisec): 10718

User: OMEGACW\bkurt
Command: C:\Windows\System32\hkcmd.exe
Start time: 2015-09-28-00:41:50
CPU time (millisec): 93

User: OMEGACW\bkurt
Command: C:\Windows\System32\igfxpers.exe
Start time: 2015-09-28-00:41:50
CPU time (millisec): 2593

User: OMEGACW\bkurt
Command: C:\Program Files\Realtek\Audio\HDA\RAVCpl64.exe
Start time: 2015-09-28-00:41:51
CPU time (millisec): 515

User: OMEGACW\bkurt
Command: C:\Program Files\Realtek\Audio\HDA\RAVBg64.exe
Start time: 2015-09-28-00:41:52
CPU time (millisec): 578

User: OMEGACW\bkurt
Command: C:\Program Files\Realtek\Audio\HDA\RAVBg64.exe
Start time: 2015-09-28-00:41:53
CPU time (millisec): 281

User: OMEGACW\bkurt
Command: C:\Program Files\Elantech\ETDCtrl.exe
Start time: 2015-09-28-00:41:54
CPU time (millisec): 100109

User: OMEGACW\bkurt
Command: C:\Windows\System32\rundll32.exe
Start time: 2015-09-28-00:41:55
CPU time (millisec): 312

User: OMEGACW\bkurt
Command: C:\Program Files\Nimi Places\Nimi Places.exe
Start time: 2015-09-28-00:41:57
CPU time (millisec): 52453

User: OMEGACW\bkurt
Command: C:\Program Files (x86)\VMware\VMware Workstation\vmware-tray.exe
Start time: 2015-09-28-00:42:03
CPU time (millisec): 671

User: OMEGACW\bkurt
Command: C:\Program Files (x86)\Adobe\Acrobat 9.0\Acrobat\acrotray.exe
Start time: 2015-09-28-00:42:08
CPU time (millisec): 500

User: OMEGACW\bkurt
Command: C:\opt64\totalcmd\TOTALCMD64.EXE
Start time: 2015-09-28-00:43:05
CPU time (millisec): 21906

User: OMEGACW\bkurt
Command: C:\opt32\npp\notepad++.exe
Start time: 2015-09-28-00:43:43
CPU time (millisec): 36015

User: OMEGACW\bkurt
Command: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Start time: 2015-09-28-00:48:07
CPU time (millisec): 3633578

User: OMEGACW\bkurt
Command: C:\opt64\totalcmd\TOTALCMD64.EXE
Start time: 2015-09-28-09:14:35
CPU time (millisec): 564062

User: OMEGACW\bkurt
Command: C:\Windows\splwow64.exe
Start time: 2015-09-28-19:19:34
CPU time (millisec): 6578

User: OMEGACW\bkurt
Command: C:\opt64\virtualbox\VirtualBox.exe
Start time: 2015-10-01-13:56:31
CPU time (millisec): 86531

User: OMEGACW\bkurt
Command: C:\opt64\virtualbox\VBoxSVC.exe
Start time: 2015-10-01-13:56:32
CPU time (millisec): 192718

User: OMEGACW\bkurt
Command: C:\opt64\virtualbox\VirtualBox.exe
Start time: 2015-10-01-13:57:01
CPU time (millisec): 62

User: OMEGACW\bkurt
Command: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Start time: 2015-10-01-21:55:51
CPU time (millisec): 31000

User: OMEGACW\bkurt
Command: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Start time: 2015-10-01-22:11:35
CPU time (millisec): 24671

User: OMEGACW\bkurt
Command: C:\opt64\netbeans-dev-jdk9-201506180405\bin\netbeans64.exe
Start time: 2015-10-01-22:12:00
CPU time (millisec): 2255062

User: OMEGACW\bkurt
Command: C:\opt64\java\jdk1.9.0\bin\java.exe
Start time: 2015-10-03-07:20:24
CPU time (millisec): 328

User: OMEGACW\bkurt
Command: C:\Windows\System32\conhost.exe
Start time: 2015-10-03-07:20:24
CPU time (millisec): 0
  • İşletim sisteminde şu an çalışan prosesler arasında en uzun süredir çalışan proses
package com.example.java9;

import java.lang.ProcessHandle.Info;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Consumer;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class LongestRunningProcess {

    public static void main(String[] args) {
        DateTimeFormatter formatter
                = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss")
                .withZone(ZoneId.systemDefault());
        Consumer<String> printUser = user -> {
            System.out.println("User: " + user);
        };
        Consumer<String> printCmd = cmd -> {
            System.out.println("Command: " + cmd);
        };
        Consumer<String> printCmdLine = cmdln -> {
            System.out.println("Command line: " + cmdln);
        };
        Consumer<String[]> printArgs = arguments -> {
            System.out.println("Arguments: " + Arrays.toString(arguments));
        };
        Consumer<Instant> printInstant = inst -> {
            System.out.println("Start time: " + formatter.format(inst));
        };
        Consumer<Duration> printCpu = duration -> {
            System.out.println("CPU time (millisec): " + duration.toMillis());
        };
        Consumer<Info> printInfo
                = info -> {
                    info.user().ifPresent(printUser);
                    info.command().ifPresent(printCmd);
                    info.commandLine().ifPresent(printCmdLine);
                    info.arguments().ifPresent(printArgs);
                    info.startInstant().ifPresent(printInstant);
                    info.totalCpuDuration().ifPresent(printCpu);
                    System.out.println();
                };        
        Instant now= Instant.now();
        Optional<Info> processInfo= 
                ProcessHandle.allProcesses()
                    .map( p -> p.info() )
                    .filter(info -> info.startInstant().isPresent())
                    .max( (p,q) -> q.startInstant().orElse(now)
                        .compareTo(p.startInstant().orElse(now)));
        processInfo.ifPresent(printInfo);
    }
}
Uygulamanın örnek ekran çıktısı:
run:
User: OMEGACW\bkurt
Command: C:\Program Files\Microsoft Mouse and Keyboard Center\itype.exe
Start time: 2015-09-28-00:40:25
CPU time (millisec): 78156

BUILD SUCCESSFUL (total time: 0 seconds)
  • İşletim sisteminde şu an çalışan prosesler arasında en çok işlemci zamanını kullanan proses
package com.example.java9;

import java.time.Duration;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Consumer;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class MostCpuConsumingProcess {

    public static void main(String[] args) {
        DateTimeFormatter formatter
                = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss")
                .withZone(ZoneId.systemDefault());
        Consumer<String> printUser = user -> {
            System.out.println("User: " + user);
        };
        Consumer<String> printCmd = cmd -> {
            System.out.println("Command: " + cmd);
        };
        Consumer<String> printCmdLine = cmdln -> {
            System.out.println("Command line: " + cmdln);
        };
        Consumer<String[]> printArgs = arguments -> {
            System.out.println("Arguments: " + Arrays.toString(arguments));
        };
        Consumer<Instant> printInstant = inst -> {
            System.out.println("Start time: " + formatter.format(inst));
        };
        Consumer<Duration> printCpu = duration -> {
            System.out.println("CPU time (millisec): " + duration.toMillis());
        };
        Consumer<ProcessHandle.Info> printInfo
                = info -> {
                    info.user().ifPresent(printUser);
                    info.command().ifPresent(printCmd);
                    info.commandLine().ifPresent(printCmdLine);
                    info.arguments().ifPresent(printArgs);
                    info.startInstant().ifPresent(printInstant);
                    info.totalCpuDuration().ifPresent(printCpu);
                    System.out.println();
                };
        Optional<ProcessHandle.Info> processInfo
                = ProcessHandle.allProcesses()
                .map(p -> p.info())
                .filter(info -> info.totalCpuDuration().isPresent())
                .max((p, q) -> p.totalCpuDuration().orElse(Duration.ZERO)
                    .compareTo(q.totalCpuDuration().orElse(Duration.ZERO)));
        processInfo.ifPresent(printInfo);
    }
}
Uygulamanın örnek ekran çıktısı:
run:
User: OMEGACW\bkurt
Command: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Start time: 2015-09-28-00:48:07
CPU time (millisec): 3667093

BUILD SUCCESSFUL (total time: 0 seconds)
  • proses adı verilen tüm prosesleri sonlandıralım
package com.example.java9;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Predicate;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class KillProcess {

    public static void main(String[] args) {
        if (args.length==0){
            System.out.println("Usage: ");
            System.out.println("ProcessKill <list of process names>");
            System.out.println("Example: \n\tProcessKill calc.exe mspaint.exe");
        }
        Predicate<ProcessHandle> processCriteria
                = p -> {
                    Optional<String> cmd = p.info().command();
                    if (cmd.isPresent()) {
                        Path path = Paths.get(cmd.get());
                        return Arrays.stream(args)
                               .anyMatch( arg -> path.getFileName().toString().equals(arg) );
                    }
                    return false;
                };
        ProcessHandle.allProcesses()
                .filter(p -> p.isAlive())
                .filter(processCriteria)
                .forEach(ProcessHandle::destroyForcibly);
    }
}
  • Verilen komutu çalıştıran ve bekçi köpeği olarak izleyen uygulama
package com.example.java9;

import java.util.concurrent.CompletableFuture;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class WatchDog {

    public static void main(String[] args) throws Exception {
        String cmd = args[0];
        do {
            Process process = Runtime.getRuntime().exec(cmd);
            ProcessHandle ph = process.toHandle();
            CompletableFuture<ProcessHandle> onExit = ph.onExit();
            onExit.get();
            System.err.println("Exit value: "+process.exitValue());
        } while (true);
    }
}
Yukarıdaki örnek uygulamaları çalıştırabilmek ve Java 9 ile gelen yenilikler ile tanışmak için makinanıza öncelikle JDK 9 kurmanız gerekir. JDK 9, şu an "Early Access" olarak erişime açık. Bu bağlantıdan elinizdeki platform için kurulum dosyalarına ulaşabilirsiniz. Java 9'da kod geliştirebilmek için uygun bir IDE bulmakta zorlanabilirsiniz. Yukarıdaki kodları "NetBeans Java 9" ile çalışabilirsiniz. 
Java 9 ile gelen yenilikleri ilerideki yazılarda incelemeye devam edeceğiz.

No comments:

Post a Comment