CPU Usage (%) MBean on Sun JVM - jvm

The overview tab of a process on jconsole shows me the CPU Usage percentage. Is there a MBean that gives me this value? What is its ObjectName?

Update: In Java 7 you can do it like so:
public static double getProcessCpuLoad() throws MalformedObjectNameException, ReflectionException, InstanceNotFoundException {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
AttributeList list = mbs.getAttributes(name, new String[]{ "ProcessCpuLoad" });
if (list.isEmpty()) return Double.NaN;
Attribute att = (Attribute)list.get(0);
Double value = (Double)att.getValue();
if (value == -1.0) return Double.NaN;
return ((int)(value * 1000) / 10.0); // returns a percentage value with 1 decimal point precision
}
----- original answer below -----
In Java 7 you can use the hidden methods of com.sun.management.OperatingSystemMXBean:
getProcessCpuLoad() // returns the CPU usage of the JVM
getSystemCpuLoad() // returns the CPU usage of the whole system
Both values are returned as a double between 0.0 and 1.0 so simply multiply by 100 to get a percentage.
com.sun.management.OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
System.out.println(osBean.getProcessCpuLoad() * 100);
System.out.println(osBean.getSystemCpuLoad() * 100);
Since these are hidden, undocumented, methods that exist in com.sun.management.OperatingSystemMXBean package and not in the java.lang.management.OperatingSystemMXBean there is a risk that they will not be available in some JVMs or in future updates, so you should decide if you're willing to take that risk or not.
see https://www.java.net/community-item/hidden-java-7-features-%E2%80%93-system-and-process-cpu-load-monitoring for more.

There does not seem to be a direct MBean within ManagementFactory. The closest is http://java.sun.com/javase/6/docs/api/java/lang/management/OperatingSystemMXBean.html#getSystemLoadAverage() which can be used to calculate the CPU used by the whole system.
However this URL has suggested a method based on the source code of jconsole

I modified a code from internet, like this, then I tested that and the result almost match the linux ps command's result.
/** below is the code */
public float getCpuUsed() {
/** get a MXBean */
com.sun.management.OperatingSystemMXBean osMXBean =
(com.sun.management.OperatingSystemMXBean)
ManagementFactory.getOperatingSystemMXBean();
/** set old timestamp values */
long previousJvmProcessCpuTime = osMXBean.getProcessCpuTime();
int sleepTime = 350;
/** sleep for a while to use to calculate */
try {
TimeUnit.MILLISECONDS.sleep(sleepTime);
} catch (InterruptedException e) {
logger.error("InterruptedException occurred while MemoryCollector sleeping...");
}
/** elapsed process time is in nanoseconds */
long elapsedProcessCpuTime = osMXBean.getProcessCpuTime() - previousJvmProcessCpuTime;
/** elapsed uptime is in milliseconds */
long elapsedJvmUptime = sleepTime ;
/** total jvm uptime on all the available processors */
//long totalElapsedJvmUptime = elapsedJvmUptime * osMXBean.getAvailableProcessors() ;
long totalElapsedJvmUptime = elapsedJvmUptime;
//System.out.println("echo cpu processors num " + osMXBean.getAvailableProcessors());
/** calculate cpu usage as a percentage value
to convert nanoseconds to milliseconds divide it by 1000000 and to get a percentage multiply it by 100 */
float cpuUsage = elapsedProcessCpuTime / (totalElapsedJvmUptime * 10000F);
return (float)(Math.round(cpuUsage*10)/10);
}

Iff you are using UNIX based OS then it's way much easier
final OperatingSystemMXBean mxBean = ManagementFactory.getOperatingSystemMXBean();
if (mxBean instanceof UnixOperatingSystemMXBean) {
return ((UnixOperatingSystemMXBean) mxBean).getSystemCpuLoad() * 100.0;
}

Related

How To Stop JVM Skipping Loop

I have my own test class that is supposed to do timing without JVM deleting anything. Some example test times of 100,000,000 reps comparing the native that Java calls from StrictMath.sin() to my own:
30 degrees
sineNative(): 18,342,858 ns (#1), 1,574,331 ns (#10)
sinCosTanNew6(): 13,751,140 ns (#1), 1,569,848 ns (#10)
60 degrees
sineNative(): 2,520,327,020 ns (#1), 2,520,108,337 ns (#10)
sinCosTanNew6(): 12,935,959 ns (#1), 1,565,365 ns (#10)
From 30 to 60 native time skyrockets * 137 while mine is ~constant. Also, some of the times are impossibly low even when repsDone returns == reps. I expect they should be > 1*reps.
CPU: G3258 # 4GHz
OS: Windows 7 HB SP1
Build Path: jre1.8.0_211
Reprex:
public final class MathTest {
private static int sysReps = 1_000_000;
private static double value = 0;
private static final double DRAD_ANGLE_30 = 0.52359877559829887307710723054658d;
private static final double DRAD_ANGLE_60 = 1.0471975511965977461542144610932d;
private static double sineNative(double angle ) {
int reps = sysReps * 100;
//int repsDone = 0;
value = 0;
long startTime, endTime, timeDif;
startTime = System.nanoTime();
for (int index = reps - 1; index >= 0; index--) {
value = Math.sin(angle);
//repsDone++;
}
endTime = System.nanoTime();
timeDif = endTime - startTime;
System.out.println("sineNative(): " + timeDif + "ns for " + reps + " sine " + value + " of angle " + angle);
//System.out.println("reps done: "+repsDone);
return value;
}
private static void testSines() {
sineNative(DRAD_ANGLE_30);
//sinCosTanNew6(IBIT_ANGLE_30);
}
/* Warm Up */
private static void repeatAll(int reps) {
for (int index = reps - 1; index >= 0; index--) {
testSines();
}
}
public static void main(String[] args) {
repeatAll(10);
}
}
I tried adding angle++ in the loop and that multiplies the times to a more reasonable level, but that messes with the math. I need a way to trick it into the running all of the code all x times. Single pass times are extremely volatile and calling nanotime() takes time, so I need the average of a large number.
The problem is that you never use/refer to the results returned by sineNative. The JIT compiler is clever enough to work out that you never use the return value, so it will just do nothing eventually. A very simple way to fix this is to add a dummy check for your return value. (e.g. if (Math.sin(angle) > 1) { System.out.println("Impossible!"); })
If you are writing benchmark like this it would be useful to use something like JMH (https://github.com/openjdk/jmh) which would automatically create a blackhole for your return variable, so that the JIT compiler will not optimise the value. (see example https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_09_Blackholes.java)

Unwanted click when using SoXR Library to do variable rate resampling

I am using the SoXR library's variable rate feature to dynamically change the sampling rate of an audio stream in real time. Unfortunately I have have noticed that an unwanted clicking noise is present when changing the rate from 1.0 to a larger value (ex: 1.01) when testing with a sine wave. I have not noticed any unwanted artifacts when changing from a value larger than 1.0 to 1.0. I looked at the wave form it was producing and it appeared as if a few samples right at rate change are transposed incorrectly.
Here's a picture of an example of a stereo 440Hz sinewave stored using signed 16bit interleaved samples:
I also was unable to find any documentation covering the variable rate feature beyond the fifth code example. Here's is my initialization code:
bool DynamicRateAudioFrameQueue::intialize(uint32_t sampleRate, uint32_t numChannels)
{
mSampleRate = sampleRate;
mNumChannels = numChannels;
mRate = 1.0;
mGlideTimeInMs = 0;
// Intialize buffer
size_t intialBufferSize = 100 * sampleRate * numChannels / 1000; // 100 ms
pFifoSampleBuffer = new FiFoBuffer<int16_t>(intialBufferSize);
soxr_error_t error;
// Use signed int16 with interleaved channels
soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
// "When creating a var-rate resampler, q_spec must be set as follows:" - example code
// Using SOXR_VR makes sense, but I'm not sure if the quality can be altered when using var-rate
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_HQ, SOXR_VR);
// Using the var-rate io-spec is undocumented beyond a single code example which states
// "The ratio of the given input rate and ouput rates must equate to the
// maximum I/O ratio that will be used: "
// My tests show this is not true
double inRate = 1.0;
double outRate = 1.0;
mSoxrHandle = soxr_create(inRate, outRate, mNumChannels, &error, &ioSpec, &qualitySpec, NULL);
if (error == 0) // soxr_error_t == 0; no error
{
mIntialized = true;
return true;
}
else
{
return false;
}
}
Any idea what may be causing this to happen? Or have a suggestion for an alternative library that is capable of variable rate audio resampling in real time?
After speaking with the developer of the SoXR library I was able to resolve this issue by adjusting the maximum ratio parameters in the soxr_create method call. The developer's response can be found here.

Blackberry - systemLock() not working

I'm trying to use the systemLock() to lock the device when the getSpeed() returns a value greater than 20 m/s.
public void locationUpdated(LocationProvider provider, Location location)
{
if(location.isValid())
{
float speed = location.getSpeed();
// Information to be displayed on the device
StringBuffer sb = new StringBuffer();
sb.append("\n");
sb.append("Speed : ");
sb.append(speed);
sb.append(" m/s");
if(speed < 20){
appMan = ApplicationManager.getApplicationManager();
appMan.lockSystem(true);
}else{
}
MyApp.this.updateLocationScreen(sb.toString());
}
}
I have a RichTextField and I can use the .settext() successfully in the if/else statement to change the RichTextField's text so I must be using the lockSystem() wrong.
Edit
if(speed > 20 || Double.isNaN(speed)){
requestForeground();
appMan = ApplicationManager.getApplicationManager();
appMan.lockSystem(true);
}else{
}
The first thing that comes to the eyes is:
to lock the device when the getSpeed() returns a value greater than 20 m/s.
and
if (speed < 20) {
appMan = ApplicationManager.getApplicationManager();
appMan.lockSystem(true);
}
From the docs on Location
public float getSpeed()
Returns:
the current ground speed in m/s for
the terminal or Float.NaN if the speed is not known
In Java, any comparison against Float.NaN will return false, so your lock screen code block won't execute if your device is returning NaN as the speed. You might want to add Double.isNaN(speed) to your condition.

IntelliSense: "#using" requires C++/CLI to be enabled

#using <mscorlib.dll>
#using <System.dll>
using namespace System;
using namespace System::Text;
using namespace System::IO;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Collections;
Errors: IntelliSense: "#using" requires C++/CLI to be enabled....
how to fix this prob!?
Your project settings are wrong. Specifically Configuration Properties, General, Common Language Runtime support.
Fall in the pit of success by starting your project by picking one of the project templates in the CLR node.
Choose Project -> Properties from the menu bar. In the Project properties window, under Configuration Properties -> General, make sure that Common Language Runtime Support is set to Common Language Runtime Support (/clr)
In VS2019 it the steps would be :
1/ Right click on the project
2/ Project
3/ Properties
4/ Configuration Properties
5/ Advanced
6/ Common Language Runtime Support change it to Common Language Runtime Support(/clr)
Enable it in your project settings (right click on the projet -> settings) the first tab should provide the option.
The MSDN has a nice example for testing the difference in performance, Parse vs tryParse:
Stopwatch Example
#include <stdio.h>
#using <System.dll>
using namespace System;
using namespace System::Diagnostics;
void DisplayTimerProperties()
{
// Display the timer frequency and resolution.
if (Stopwatch::IsHighResolution)
{
Console::WriteLine("Operations timed using the system's high-resolution performance counter.");
}
else
{
Console::WriteLine("Operations timed using the DateTime class.");
}
Int64 frequency = Stopwatch::Frequency;
Console::WriteLine(" Timer frequency in ticks per second = {0}", frequency);
Int64 nanosecPerTick = (1000L * 1000L * 1000L) / frequency;
Console::WriteLine(" Timer is accurate within {0} nanoseconds", nanosecPerTick);
}
void TimeOperations()
{
Int64 nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch::Frequency;
const long numIterations = 10000;
// Define the operation title names.
array<String^>^operationNames = { "Operation: Int32.Parse(\"0\")","Operation: Int32.TryParse(\"0\")","Operation: Int32.Parse(\"a\")","Operation: Int32.TryParse(\"a\")" };
// Time four different implementations for parsing
// an integer from a string.
for (int operation = 0; operation <= 3; operation++)
{
// Define variables for operation statistics.
Int64 numTicks = 0;
Int64 numRollovers = 0;
Int64 maxTicks = 0;
Int64 minTicks = Int64::MaxValue;
int indexFastest = -1;
int indexSlowest = -1;
Int64 milliSec = 0;
Stopwatch ^ time10kOperations = Stopwatch::StartNew();
// Run the current operation 10001 times.
// The first execution time will be tossed
// out, since it can skew the average time.
for (int i = 0; i <= numIterations; i++)
{
Int64 ticksThisTime = 0;
int inputNum;
Stopwatch ^ timePerParse;
switch (operation)
{
case 0:
// Parse a valid integer using
// a try-catch statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch::StartNew();
try
{
inputNum = Int32::Parse("0");
}
catch (FormatException^)
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse->Stop();
ticksThisTime = timePerParse->ElapsedTicks;
break;
case 1:
// Parse a valid integer using
// the TryParse statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch::StartNew();
if (!Int32::TryParse("0", inputNum))
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse->Stop();
ticksThisTime = timePerParse->ElapsedTicks;
break;
case 2:
// Parse an invalid value using
// a try-catch statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch::StartNew();
try
{
inputNum = Int32::Parse("a");
}
catch (FormatException^)
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse->Stop();
ticksThisTime = timePerParse->ElapsedTicks;
break;
case 3:
// Parse an invalid value using
// the TryParse statement.
// Start a new stopwatch timer.
timePerParse = Stopwatch::StartNew();
if (!Int32::TryParse("a", inputNum))
{
inputNum = 0;
}
// Stop the timer, and save the
// elapsed ticks for the operation.
timePerParse->Stop();
ticksThisTime = timePerParse->ElapsedTicks;
break;
default:
break;
}
// Skip over the time for the first operation,
// just in case it caused a one-time
// performance hit.
if (i == 0)
{
time10kOperations->Reset();
time10kOperations->Start();
}
else
{
// Update operation statistics
// for iterations 1-10001.
if (maxTicks < ticksThisTime)
{
indexSlowest = i;
maxTicks = ticksThisTime;
}
if (minTicks > ticksThisTime)
{
indexFastest = i;
minTicks = ticksThisTime;
}
numTicks += ticksThisTime;
if (numTicks < ticksThisTime)
{
// Keep track of rollovers.
numRollovers++;
}
}
}
// Display the statistics for 10000 iterations.
time10kOperations->Stop();
milliSec = time10kOperations->ElapsedMilliseconds;
Console::WriteLine();
Console::WriteLine("{0} Summary:", operationNames[operation]);
Console::WriteLine(" Slowest time: #{0}/{1} = {2} ticks", indexSlowest, numIterations, maxTicks);
Console::WriteLine(" Fastest time: #{0}/{1} = {2} ticks", indexFastest, numIterations, minTicks);
Console::WriteLine(" Average time: {0} ticks = {1} nanoseconds", numTicks / numIterations, (numTicks * nanosecPerTick) / numIterations);
Console::WriteLine(" Total time looping through {0} operations: {1} milliseconds", numIterations, milliSec);
}
}
int main()
{
DisplayTimerProperties();
Console::WriteLine();
Console::WriteLine("Press the Enter key to begin:");
Console::ReadLine();
Console::WriteLine();
TimeOperations();
getchar();
}
//Operations timed using the system's high-resolution performance counter.
//Timer frequency in ticks per second = 3319338
//Timer is accurate within 301 nanoseconds
//
//Press the Enter key to begin :
//
//
//
//Operation : Int32.Parse("0") Summary :
// Slowest time : #4483 / 10000 = 95 ticks
// Fastest time : #3 / 10000 = 0 ticks
// Average time : 0 ticks = 99 nanoseconds
// Total time looping through 10000 operations : 1 milliseconds
//
// Operation : Int32.TryParse("0") Summary :
// Slowest time : #7720 / 10000 = 187 ticks
// Fastest time : #1 / 10000 = 0 ticks
// Average time : 0 ticks = 109 nanoseconds
// Total time looping through 10000 operations : 1 milliseconds
//
// Operation : Int32.Parse("a") Summary :
// Slowest time : #3701 / 10000 = 2388 ticks
// Fastest time : #2698 / 10000 = 102 ticks
// Average time : 116 ticks = 35109 nanoseconds
// Total time looping through 10000 operations : 352 milliseconds
//
// Operation : Int32.TryParse("a") Summary :
// Slowest time : #8593 / 10000 = 23 ticks
// Fastest time : #1 / 10000 = 0 ticks
// Average time : 0 ticks = 88 nanoseconds
// Total time looping through 10000 operations : 1 milliseconds
If you are using Visual Studio, you might have to do some installations pre-hand. To install those, open the Visual Studio Installer from the Windows Start menu. Make sure that the Desktop development with C++ tile is checked, and in the Optional components section, also check C++/CLI Support.

generating 9 digit ids without database sequence

I'd like to create 9-digit numeric ids that are unique across machines. I'm currently using a database sequence for this, but am wondering if it could be done without one. The sequences will be used for X12 EDI transactions, so they don't have to be unique forever. Maybe even only unique for 24 hours.
My only idea:
Each server has a 2 digit server identifier.
Each server maintains a file that essentially keeps track of a local sequence.
id = + <7 digit sequence which wraps>
My biggest problem with this is what to do if the hard-drive fails. I wouldn't know where it left off.
All of my other ideas essentially end up re-creating a centralized database sequence.
Any thoughts?
The Following
{XX}{dd}{HHmm}{N}
Where {XX} is the machine number {dd} is the day of the month {HHmm} current time (24hr) and {N} a sequential number.
A hd crash will take more than a minute so starting at 0 again is not a problem.
You can also replace {dd} with {ss} for seconds, depending on requirements. Uniqueness period vs. requests per minute.
If HD fails you can just set new and unused 2 digit server identifier and be sure that the number is unique (for 24 hours at least)
How about generating GUIDs (ensures uniqueness) and then using some sort of hash function to turn the GUID into a 9-digit number?
Just off the top of my head...
Use a variation on:
md5(uniqid(rand(), true));
Just a thought.
In my recent project I also come across this requirement, to generate N digit long sequence number without any database.
This is actually a good Interview question, because there are consideration on performance and software crash recovery. Further Reading if interested.
The following code has these features:
Prefix each sequence with a prefix.
Sequence cache like Oracle Sequence.
Most importantly, there is recovery logic to resume sequence from software crash.
Complete implementation attached:
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang.StringUtils;
/**
* This is a customized Sequence Generator which simulates Oracle DB Sequence Generator. However the master sequence
* is stored locally in the file as there is no access to Oracle database. The output format is "prefix" + number.
* <p>
* <u><b>Sample output:</u></b><br>
* 1. FixLengthIDSequence(null,null,15,0,99,0) will generate 15, 16, ... 99, 00<br>
* 2. FixLengthIDSequence(null,"K",1,1,99,0) will generate K01, K02, ... K99, K01<br>
* 3. FixLengthIDSequence(null,"SG",100,2,9999,100) will generate SG0100, SG0101, ... SG8057, (in case server crashes, the new init value will start from last cache value+1) SG8101, ... SG9999, SG0002<br>
*/
public final class FixLengthIDSequence {
private static String FNAME;
private static String PREFIX;
private static AtomicLong SEQ_ID;
private static long MINVALUE;
private static long MAXVALUE;
private static long CACHEVALUE;
// some internal working values.
private int iMaxLength; // max numeric length excluding prefix, for left padding zeros.
private long lNextSnapshot; // to keep track of when to update sequence value to file.
private static boolean bInit = false; // to enable ShutdownHook routine after program has properly initialized
static {
// Inspiration from http://stackoverflow.com/questions/22416826/sequence-generator-in-java-for-unique-id#35697336.
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (bInit) { // Without this, saveToLocal may hit NullPointerException.
saveToLocal(SEQ_ID.longValue());
}
}));
}
/**
* This POJO style constructor should be initialized via Spring Singleton. Otherwise, rewrite this constructor into Singleton design pattern.
*
* #param sFilename This is the absolute file path to store the sequence number. To reset the sequence, this file needs to be removed manually.
* #param prefix The hard-coded identifier.
* #param initvalue
* #param minvalue
* #param maxvalue
* #param cache
* #throws Exception
*/
public FixLengthIDSequence(String sFilename, String prefix, long initvalue, long minvalue, long maxvalue, int cache) throws Exception {
bInit = false;
FNAME = (sFilename==null)?"C:\\Temp\\sequence.txt":sFilename;
PREFIX = (prefix==null)?"":prefix;
SEQ_ID = new AtomicLong(initvalue);
MINVALUE = minvalue;
MAXVALUE = maxvalue; iMaxLength = Long.toString(MAXVALUE).length();
CACHEVALUE = (cache <= 0)?1:cache; lNextSnapshot = roundUpNumberByMultipleValue(initvalue, cache); // Internal cache is always 1, equals no cache.
// If sequence file exists and valid, restore the saved sequence.
java.io.File f = new java.io.File(FNAME);
if (f.exists()) {
String[] saSavedSequence = loadToString().split(",");
if (saSavedSequence.length != 6) {
throw new Exception("Local Sequence file is not valid");
}
PREFIX = saSavedSequence[0];
//SEQ_ID = new AtomicLong(Long.parseLong(saSavedSequence[1])); // savedInitValue
MINVALUE = Long.parseLong(saSavedSequence[2]);
MAXVALUE = Long.parseLong(saSavedSequence[3]); iMaxLength = Long.toString(MAXVALUE).length();
CACHEVALUE = Long.parseLong(saSavedSequence[4]);
lNextSnapshot = Long.parseLong(saSavedSequence[5]);
// For sequence number recovery
// The rule to determine to continue using SEQ_ID or lNextSnapshot as subsequent sequence number:
// If savedInitValue = savedSnapshot, it was saved by ShutdownHook -> use SEQ_ID.
// Else if saveInitValue < savedSnapshot, it was saved by periodic Snapshot -> use lNextSnapshot+1.
if (saSavedSequence[1].equals(saSavedSequence[5])) {
long previousSEQ = Long.parseLong(saSavedSequence[1]);
SEQ_ID = new AtomicLong(previousSEQ);
lNextSnapshot = roundUpNumberByMultipleValue(previousSEQ,CACHEVALUE);
} else {
SEQ_ID = new AtomicLong(lNextSnapshot+1); // SEQ_ID starts fresh from lNextSnapshot+!.
lNextSnapshot = roundUpNumberByMultipleValue(SEQ_ID.longValue(),CACHEVALUE);
}
}
// Catch invalid values.
if (minvalue < 0) {
throw new Exception("MINVALUE cannot be less than 0");
}
if (maxvalue < 0) {
throw new Exception("MAXVALUE cannot be less than 0");
}
if (minvalue >= maxvalue) {
throw new Exception("MINVALUE cannot be greater than MAXVALUE");
}
if (cache >= maxvalue) {
throw new Exception("CACHE value cannot be greater than MAXVALUE");
}
// Save the next Snapshot.
saveToLocal(lNextSnapshot);
bInit = true;
}
/**
* Equivalent to Oracle Sequence nextval.
* #return String because Next Value is usually left padded with zeros, e.g. "00001".
*/
public String nextVal() {
if (SEQ_ID.longValue() > MAXVALUE) {
SEQ_ID.set(MINVALUE);
lNextSnapshot = roundUpNumberByMultipleValue(MINVALUE,CACHEVALUE);
}
if (SEQ_ID.longValue() > lNextSnapshot) {
lNextSnapshot = roundUpNumberByMultipleValue(lNextSnapshot,CACHEVALUE);
saveToLocal(lNextSnapshot);
}
return PREFIX.concat(StringUtils.leftPad(Long.toString(SEQ_ID.getAndIncrement()),iMaxLength,"0"));
}
/**
* Store sequence value into the local file. This routine is called either by Snapshot or ShutdownHook routines.<br>
* If called by Snapshot, currentCount == Snapshot.<br>
* If called by ShutdownHook, currentCount == current SEQ_ID.
* #param currentCount - This value is inserted by either Snapshot or ShutdownHook routines.
*/
private static void saveToLocal (long currentCount) {
try (java.io.Writer w = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new java.io.FileOutputStream(FNAME), "utf-8"))) {
w.write(PREFIX + "," + SEQ_ID.longValue() + "," + MINVALUE + "," + MAXVALUE + "," + CACHEVALUE + "," + currentCount);
w.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Load the sequence file content into String.
* #return
*/
private String loadToString() {
try {
return new String(java.nio.file.Files.readAllBytes(java.nio.file.Paths.get(FNAME)));
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* Utility method to round up num to next multiple value. This method is used to calculate the next cache value.
* <p>
* (Reference: http://stackoverflow.com/questions/18407634/rounding-up-to-the-nearest-hundred)
* <p>
* <u><b>Sample output:</b></u>
* <pre>
* System.out.println(roundUpNumberByMultipleValue(9,10)); = 10
* System.out.println(roundUpNumberByMultipleValue(10,10)); = 20
* System.out.println(roundUpNumberByMultipleValue(19,10)); = 20
* System.out.println(roundUpNumberByMultipleValue(100,10)); = 110
* System.out.println(roundUpNumberByMultipleValue(109,10)); = 110
* System.out.println(roundUpNumberByMultipleValue(110,10)); = 120
* System.out.println(roundUpNumberByMultipleValue(119,10)); = 120
* </pre>
*
* #param num Value must be greater and equals to positive integer 1.
* #param multiple Value must be greater and equals to positive integer 1.
* #return
*/
private long roundUpNumberByMultipleValue(long num, long multiple) {
if (num<=0) num=1;
if (multiple<=0) multiple=1;
if (num % multiple != 0) {
long division = (long) ((num / multiple) + 1);
return division * multiple;
} else {
return num + multiple;
}
}
/**
* Main method for testing purpose.
* #param args
*/
public static void main(String[] args) throws Exception {
//FixLengthIDSequence(Filename, prefix, initvalue, minvalue, maxvalue, cache)
FixLengthIDSequence seq = new FixLengthIDSequence(null,"H",50,1,999,10);
for (int i=0; i<12; i++) {
System.out.println(seq.nextVal());
Thread.sleep(1000);
//if (i==8) { System.exit(0); }
}
}
}
To test the code, let the sequence run normally. You can press Ctrl+C to simulate the server crash. The next sequence number will continue from NextSnapshot+1.
Cold you use the first 9 digits of some other source of unique data like:
a random number
System Time
Uptime
Having thaught about it for two seconds, none of those are unique on there own but you could use them as seed values for hash functions as was suggested in another answer.