I would like to know since i'm fan of java 14 if replacing null checks with Optional.ofNullable
is safe for this language. I know a simple null check doesn't cost any memory while new creating new objects like optional cost but i guess it has zero performance impact or memory impact. Can someone enlight me?
The code for my game was like:
if (item!= null)
{
if (item.getCrystal() == Crystal.A)
{
player.getInventory().addItem(inventoryItem);
}
}
to something which i enjoy and i find cool
Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A).ifPresent(k -> player.getInventory.addItem(i));
Can someone enlight me that i'm ok with it? Maybe is cool but cost a lot? I don't know.
Thanks a lot.
In simple cases like this, the just in time compiler can likely elide the object allocation, or at least allocate it on the stack, so the overhead is negligible.
Here's a small benchmark:
public abstract class Benchmark {
final String name;
public Benchmark(String name) {
this.name = name;
}
#Override
public String toString() {
return name + "\t" + time() + " ns / iteration";
}
private BigDecimal time() {
try {
// automatically detect a reasonable iteration count (and trigger just in time compilation of the code under test)
int iterations;
long duration = 0;
for (iterations = 1; iterations < 1_000_000_000 && duration < 1_000_000_000; iterations *= 2) {
long start = System.nanoTime();
run(iterations);
duration = System.nanoTime() - start;
cleanup();
}
return new BigDecimal((duration) * 1000 / iterations).movePointLeft(3);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
/**
* Executes the code under test.
* #param iterations
* number of iterations to perform
* #return any value that requires the entire code to be executed (to
* prevent dead code elimination by the just in time compiler)
* #throws Throwable
* if the test could not complete successfully
*/
protected abstract Object run(int iterations) throws Throwable;
/**
* Cleans up after a run, setting the stage for the next.
*/
protected void cleanup() {
// do nothing
}
public static void main(String[] args) throws Exception {
Integer[] a = {null, -1, null, 1}; // mix nulls and real values
System.out.println(new Benchmark("Optional") {
#Override
protected Object run(int iterations) throws Throwable {
int[] sum = {0};
for (int i = 0; i < iterations; i++) {
Optional.ofNullable(a[i & 3]).filter(k -> k > 0).ifPresent(k -> sum[0] += k);
}
return sum[0];
}
});
System.out.println(new Benchmark("if != null") {
#Override
protected Object run(int iterations) throws Throwable {
int[] sum = {0};
for (int i = 0; i < iterations; i++) {
var k = a[i & 3];
if (k != null && k % 2 != 0) {
sum[0] += k;
}
}
return sum[0];
}
});
}
}
This shows that the overhead of using an Optional is about 1 ns, i.e. a modern CPU can construct and evaluate about 1 billion Optional objects per second. In all but the most extreme and contrived of workloads, the use of Optional will not affect performance enough for humans to notice.
The decision to use Optional should therefore not be guided by performance considerations, but by which version allows yourself to express yourself more clearly and simply.
In this case, I'd argue that the if statement is actually more readable. Sure, you've squashed everything onto a single line, but you could do the same with an if statement:
if (item != null && item.getCrystal() == Crystal.A) player.getInventory().addItem(inventoryItem);
If you do that, you'll notice that the if statement is actually shorter and more to the point than your version:
Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A).ifPresent(k -> player.getInventory.addItem(i));
Of course, in real code you'll probably want to keep your lines reasonably short, so the comparison is
if (item != null && item.getCrystal() == Crystal.A) {
player.getInventory().addItem(inventoryItem);
}
vs
Optional.ofNullable(item).filter(i -> i.getCrystal() == Crystal.A)
.ifPresent(k -> player.getInventory.addItem(i));
Again, I find the first version more readable, because it contains fewer words.
I am trying to find a way to generate inner loops on demand (and have the depth as a variable).
In the following example, I am trying to generate a list of references such as jobo.2.2.2.2.2.2 where each .2 is added in the inner loop.
Here is what I have at the moment when I implement the new loop manually for 5 level of depth (i, j, k, l):
public void buildTaskList(){
String jobName ="jobo";
String last="";
long max=3;
List<String> tasks = new ArrayList<>();
for (long i = 1; i <= max; i++) {
for (long j = 1; j <= max; j++) {
if (j==max){
last="*";
tasks.add(jobName+"."+i+"."+j+last);
}else {
last="";
for (long k = 1; k <= max; k++) {
if (k==max){
last="*";
tasks.add(jobName+"."+i+"."+j+"."+k+last);
}else {
last="";
for (long l = 1; l <= max; l++) {
if (l==max){
last="*";
tasks.add(jobName+"."+i+"."+j+"."+k+"."+l+last);
}else{
last="";
for (long m = 1; m <= max; m++) {
if (m==max){
last="*";
tasks.add(jobName+"."+i+"."+j+"."+k+"."+l+"."+m+last);
}else{
last="";
for (long n = 1; n <= max; n++) {
if (n==max)last="*";else last="";
tasks.add(jobName+"."+i+"."+j+"."+k+"."+l+"."+m+"."+n+last);
}
}
}
}
}
}
}
}
}
}
tasks.add(jobName+"."+(max+1)+last);
System.out.println(tasks);
}
The result here is:
jobo.1.1.1.1.1.1, jobo.1.1.1.1.1.2, jobo.1.1.1.1.1.3*, jobo.1.1.1.1.2.1, jobo.1.1.1.1.2.2, jobo.1.1.1.1.2.3*, jobo.1.1.1.1.3*, jobo.1.1.1.2.1.1, jobo.1.1.1.2.1.2, jobo.1.1.1.2.1.3*, jobo.1.1.1.2.2.1, jobo.1.1.1.2.2.2, jobo.1.1.1.2.2.3*, jobo.1.1.1.2.3*, jobo.1.1.1.3*, jobo.1.1.2.1.1.1, jobo.1.1.2.1.1.2, jobo.1.1.2.1.1.3*, jobo.1.1.2.1.2.1, jobo.1.1.2.1.2.2, jobo.1.1.2.1.2.3*, jobo.1.1.2.1.3*, jobo.1.1.2.2.1.1, jobo.1.1.2.2.1.2, jobo.1.1.2.2.1.3*, jobo.1.1.2.2.2.1, jobo.1.1.2.2.2.2, jobo.1.1.2.2.2.3*, jobo.1.1.2.2.3*, jobo.1.1.2.3*, jobo.1.1.3*, jobo.1.2.1.1.1.1, jobo.1.2.1.1.1.2, jobo.1.2.1.1.1.3*, jobo.1.2.1.1.2.1, jobo.1.2.1.1.2.2, jobo.1.2.1.1.2.3*, jobo.1.2.1.1.3*, jobo.1.2.1.2.1.1, jobo.1.2.1.2.1.2, jobo.1.2.1.2.1.3*, jobo.1.2.1.2.2.1, jobo.1.2.1.2.2.2, jobo.1.2.1.2.2.3*, jobo.1.2.1.2.3*, jobo.1.2.1.3*, jobo.1.2.2.1.1.1, jobo.1.2.2.1.1.2, jobo.1.2.2.1.1.3*, jobo.1.2.2.1.2.1, jobo.1.2.2.1.2.2, jobo.1.2.2.1.2.3*, jobo.1.2.2.1.3*, jobo.1.2.2.2.1.1, jobo.1.2.2.2.1.2, jobo.1.2.2.2.1.3*, jobo.1.2.2.2.2.1, jobo.1.2.2.2.2.2, jobo.1.2.2.2.2.3*, jobo.1.2.2.2.3*, jobo.1.2.2.3*, jobo.1.2.3*, jobo.1.3*, jobo.2.1.1.1.1.1, jobo.2.1.1.1.1.2, jobo.2.1.1.1.1.3*, jobo.2.1.1.1.2.1, jobo.2.1.1.1.2.2, jobo.2.1.1.1.2.3*, jobo.2.1.1.1.3*, jobo.2.1.1.2.1.1, jobo.2.1.1.2.1.2, jobo.2.1.1.2.1.3*, jobo.2.1.1.2.2.1, jobo.2.1.1.2.2.2, jobo.2.1.1.2.2.3*, jobo.2.1.1.2.3*, jobo.2.1.1.3*, jobo.2.1.2.1.1.1, jobo.2.1.2.1.1.2, jobo.2.1.2.1.1.3*, jobo.2.1.2.1.2.1, jobo.2.1.2.1.2.2, jobo.2.1.2.1.2.3*, jobo.2.1.2.1.3*, jobo.2.1.2.2.1.1, jobo.2.1.2.2.1.2, jobo.2.1.2.2.1.3*, jobo.2.1.2.2.2.1, jobo.2.1.2.2.2.2, jobo.2.1.2.2.2.3*, jobo.2.1.2.2.3*, jobo.2.1.2.3*, jobo.2.1.3*, jobo.2.2.1.1.1.1, jobo.2.2.1.1.1.2, jobo.2.2.1.1.1.3*, jobo.2.2.1.1.2.1, jobo.2.2.1.1.2.2, jobo.2.2.1.1.2.3*, jobo.2.2.1.1.3*, jobo.2.2.1.2.1.1, jobo.2.2.1.2.1.2, jobo.2.2.1.2.1.3*, jobo.2.2.1.2.2.1, jobo.2.2.1.2.2.2, jobo.2.2.1.2.2.3*, jobo.2.2.1.2.3*, jobo.2.2.1.3*, jobo.2.2.2.1.1.1, jobo.2.2.2.1.1.2, jobo.2.2.2.1.1.3*, jobo.2.2.2.1.2.1, jobo.2.2.2.1.2.2, jobo.2.2.2.1.2.3*, jobo.2.2.2.1.3*, jobo.2.2.2.2.1.1, jobo.2.2.2.2.1.2, jobo.2.2.2.2.1.3*, jobo.2.2.2.2.2.1, jobo.2.2.2.2.2.2, jobo.2.2.2.2.2.3*, jobo.2.2.2.2.3*, jobo.2.2.2.3*, jobo.2.2.3*, jobo.2.3*, jobo.3.1.1.1.1.1, jobo.3.1.1.1.1.2, jobo.3.1.1.1.1.3*, jobo.3.1.1.1.2.1, jobo.3.1.1.1.2.2, jobo.3.1.1.1.2.3*, jobo.3.1.1.1.3*, jobo.3.1.1.2.1.1, jobo.3.1.1.2.1.2, jobo.3.1.1.2.1.3*, jobo.3.1.1.2.2.1, jobo.3.1.1.2.2.2, jobo.3.1.1.2.2.3*, jobo.3.1.1.2.3*, jobo.3.1.1.3*, jobo.3.1.2.1.1.1, jobo.3.1.2.1.1.2, jobo.3.1.2.1.1.3*, jobo.3.1.2.1.2.1, jobo.3.1.2.1.2.2, jobo.3.1.2.1.2.3*, jobo.3.1.2.1.3*, jobo.3.1.2.2.1.1, jobo.3.1.2.2.1.2, jobo.3.1.2.2.1.3*, jobo.3.1.2.2.2.1, jobo.3.1.2.2.2.2, jobo.3.1.2.2.2.3*, jobo.3.1.2.2.3*, jobo.3.1.2.3*, jobo.3.1.3*, jobo.3.2.1.1.1.1, jobo.3.2.1.1.1.2, jobo.3.2.1.1.1.3*, jobo.3.2.1.1.2.1, jobo.3.2.1.1.2.2, jobo.3.2.1.1.2.3*, jobo.3.2.1.1.3*, jobo.3.2.1.2.1.1, jobo.3.2.1.2.1.2, jobo.3.2.1.2.1.3*, jobo.3.2.1.2.2.1, jobo.3.2.1.2.2.2, jobo.3.2.1.2.2.3*, jobo.3.2.1.2.3*, jobo.3.2.1.3*, jobo.3.2.2.1.1.1, jobo.3.2.2.1.1.2, jobo.3.2.2.1.1.3*, jobo.3.2.2.1.2.1, jobo.3.2.2.1.2.2, jobo.3.2.2.1.2.3*, jobo.3.2.2.1.3*, jobo.3.2.2.2.1.1, jobo.3.2.2.2.1.2, jobo.3.2.2.2.1.3*, jobo.3.2.2.2.2.1, jobo.3.2.2.2.2.2, jobo.3.2.2.2.2.3*, jobo.3.2.2.2.3*, jobo.3.2.2.3*, jobo.3.2.3*, jobo.3.3*, jobo.4*
Anyone knows how this can be simplified and controlled by a variable int depth=123; for example?
Thanks
This option avoids recursion, and simply counts as you would when deciding the next element in the sequence:
private static class LevelGenerator implements Iterator<String> {
private int[] current; // min,min,min => min,min,min+1 => ... max,max,max
private int min, max; // at each position in current[] array
private String next; // to be returned when next() is called
public LevelGenerator(int levels, int min, int max) {
this.current = new int[levels];
for (int i=0; i<levels; i++) this.current[i] = min;
this.next = output();
this.min = min;
this.max = max;
}
/**
* Int array to string
*/
private String output() {
StringBuilder sb = new StringBuilder();
for (int i : current) sb.append("." + i);
return sb.toString();
}
/**
* Updates current and next
* counts as a human would: increments the last index that is not yet `max`,
* and then places all elements after it to `min`
*/
private String step() {
for (int i=current.length-1; i>=0; i--) {
if (current[i] < max) {
current[i] ++;
for (int j=i+1; j<current.length; j++) {
current[j] = min;
}
return output(); // next step is ready
}
}
return null; // no next step
}
#Override
public String next() {
if (next == null) throw new IllegalStateException("iteration is finished");
String output = next;
next = step();
return output;
}
#Override
public boolean hasNext() {
return next != null;
}
}
public static void main(String ... args) {
LevelGenerator l = new LevelGenerator(3, 1, 4);
while (l.hasNext()) {
System.out.println("job" + l.next());
}
}
The output for this example would be:
job.1.1.1
job.1.1.2
job.1.1.3
job.1.1.4
job.1.2.1
job.1.2.2
job.1.2.3
job.1.2.4
job.1.3.1
job.1.3.2
job.1.3.3
job.1.3.4
job.1.4.1
job.1.4.2
job.1.4.3
job.1.4.4
job.2.1.1
...
job.4.4.4
You can use Recursion (see wiki https://en.wikipedia.org/wiki/Recursion_(computer_science))
for example (draft, not checking)
#Test
public void buildTaskList1() {
String jobName ="job";
int depth=5;
int max=3;
List<String> tasks = new ArrayList<>();
for (long i = 1; i <= max; i++) {
buildTaskListRecursion(max, depth, tasks, jobName + "."+i);
}
tasks.add(jobName+"."+(max+1)+"*");
}
public void buildTaskListRecursion(int max,int depth, List<String> tasks, String jobName){
String last="";
for (long j = 1; j <= max; j++) {
if (j==max){
last="*";
tasks.add(jobName+"."+j+last);
}else {
depth--;
if(depth > 0) {
buildTaskListRecursion(max, depth, tasks, jobName+"."+j);
} else {
tasks.add(jobName+"."+j);
}
}
}
}
Yes
1. Support indexes
Create a stack of indexes of the size of depth.
2. Handle the levels properly
You need a currentDepth index to know where you were. This is 0 at first. Whenever an item is increased, push a new item to the stack with 0 as index. Whenever an item is going beyond max, pop it from the stack and increment the previous element. When the first element is popped, you completed all the work
3. You will need to logically know where you were.
Alternatively you could generate code
But that's much more complicated.
EDIT
In agreement with Bdzzaid's legitimate request, I will briefly talk about the Composite Design Pattern. First, let's see a diagram from the page he shared with us:
Source: https://dzone.com/articles/composite-design-pattern-in-java-1
That's a good read I can wholeheartedly recommend to future readers. The idea is that we use the composition of very similar components in a tree-like manner. The pattern is applied on a stack in our case, which can be thought about as a tree having a single branch in all cases. The reason this is beneficial to think about in this way is that we might want to add support for multiple loops, maybe even in an assymmetryc manner at some point. Now, the components are the levels/indexes in our case and they, together form a composition of the stack (or, in more general terms, the tree).
This pattern can be reused in many different situations, so it is advisable to get familiar with it if you not already have.
So I'm trying to complete an exercise where I've been asked to implement a method that does a binary search in an ArrayList of objects. From the exercise:
Binary search
In the Main-class, implement a method public static int binarySearch(ArrayList<Book> books, int searchedId), which searches the list it received as a parameter, for a book with an id variable that matches the value of searchedId variable it received as a parameter. If that book is found the method, should return the index it's located at, in the list it received as a parameter. If the book isn't found, the method should return the value -1.
The method must be implemented as a binary search, which assumes the list is ordered. You should also assume, that the ids towards the beginning of the list, are always smaller than the ids towards the end of the list.
I have created two methods, one to check whether the arraylist is sorted (isItSorted) and the other one that will perform the binary search if the aforementioned method evaluates to true (binarySearch). Please see below:
public static boolean isItSorted(ArrayList<Book> books) {
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
if (!(boo.contains("false"))) {
return true;
}
return false;
}
public static int binarySearch(ArrayList<Book> books, long searchedId) {
if (searchedId < 0 || books.isEmpty()) {
return -1;
} else if (isItSorted(books)) {
int start = 0;
int end = books.size() - 1;
int middle = (start + end) / 2;
if (books.get(middle).getId() == searchedId) {
return middle;
} else if (books.get(middle).getId() > searchedId) {
end = middle - 1;
} else if (books.get(middle).getId() < searchedId) {
start = middle + 1;
}
while (start <= end) {
if (books.get(start).getId() == searchedId) {
return start;
}
start++;
}
}
return -1;
}
Inside these java files, there's a test package that tests whether my solution is correct or not. While 95% of the tests are successful, when it reaches the method below (where it compares the time of execution compared to my other method (linear search)), I get the error Java outOfMemory heap Space.
I use NetBeans. I've already tried the JVM commands.
My solution seems to work with every number of objects I've tried, so perhaps there's something wrong with the test code below?
#Test
#Points("07-05.2")
public void binarySearchIsFasterThanLinearSearch() throws Throwable {
ArrayList<Book> books = generateBooks(10000);
Collections.sort(books, (k1, k2) -> k1.getId() - k2.getId());
int searched = 1000001;
long bSearchStart = System.nanoTime();
int binarySearchId = Searching.binarySearch(books, searched);
long bSearchEnd = System.nanoTime();
assertTrue("When binary search does not find what was searched for, it must return -1", binarySearchId == -1);
long lSearchStart = System.nanoTime();
int linearSearchId = Searching.linearSearch(books, searched);
long lSearchEnd = System.nanoTime();
assertTrue("When linear search does not find what was searched for, it must return -1", linearSearchId == -1);
long bSearchTime = bSearchEnd - bSearchStart;
long lSearchTime = lSearchEnd - lSearchStart;
assertTrue("When there are 10000 books to search, and the searched book is not found, binary search should be a lot faster than linear search. Current this isn't so", bSearchTime * 2 < lSearchTime);
}
ArrayList<String> boo = new ArrayList<>();
String isItSorted = "";
for (int i = 0; i < books.size(); i++) {
for (int j = i + 1; j < books.size(); j++) {
if (books.get(i).getId() < books.get(j).getId()) {
isItSorted = "true";
boo.add(isItSorted);
} else {
isItSorted = "false";
boo.add(isItSorted);
}
}
}
Adds on the order of 100 million items to the ArrayList boo.
If you want to check if something is sorted you can use much simpler code:
Book prev = books[0];
for (int i = 1; i < books.size(); i++) {
if (prev.getId() > books[i].getId())
return false;
}
return true;
But you shouldn't need to call it inside binarySearch() because that will defeat the purpose of binarySearch() and make it as slow as linearSearch().
I am aware there are multiple threads like my assignment below, but I just can't figure it out. I can't exactly figure out the mistake. Help would be appreciated.
I am trying to do this program:
Everything works fine unless I input the same chains or similar (for example ACTG and ACTG or ACTG and ACTGCCCC), when it tells me
string index out of range
This is that part of my code:
int tries=0;
int pos=-1;
int k;
for (int i=0; i<longDNA.length(); i++) {
tries=0;
k=i;
for (int j=0; j<shortDNA.length(); j++) {
char s=shortDNA.charAt(j);
char l=longDNA.charAt(k);
if (canConnect(s,l)) {
tries+=1;
k+=1;
}
}
if (tries==shortDNA.length()-1) {
pos=i-1;
break;
}
}
Let's call the two DNA strings longer and shorter. In order for shorter to attach somewhere on longer, a sequence of bases complementary to shorter must be found somewhere in longer, e.g. if there is ACGT in shorter, then you need to find TGCA somewhere in longer.
So, if you take shorter and flip all of its bases to their complements:
char[] cs = shorter.toCharArray();
for (int i = 0; i < cs.length; ++i) {
// getComplement changes A->T, C->G, G->C, T->A,
// and throws an exception in all other cases
cs[i] = getComplement(cs[i]);
}
String shorterComplement = new String(cs);
For the examples given in your question, the complement of TTGCC is AACGG, and the complement of TGC is ACG.
Then all you have to do is to find shorterComplement within longer. You can do this trivially using indexOf:
return longer.indexOf(shorterComplement);
Of course, if the point of the exercise is to learn how to do string matching, you can look at well-known algorithms for doing the equivalent of indexOf. For instance, Wikipedia has a category for String matching algorithms.
I tried to replicate your full code as fast as I could, I'm not sure if I fixed the problem but you don't get any errors.
Please try it and see if it works.
I hope you get this in time and good luck!
import java.util.Arrays;
public class DNA {
public static void main(String[] args) {
System.out.println(findFirstMatchingPosition("ACTG", "ACTG"));
}
public static int findFirstMatchingPosition(String shortDNA, String longDNA) {
int positionInLong = 0;
int positionInShort;
while (positionInLong < longDNA.length()) {
positionInShort = 0;
while(positionInShort < shortDNA.length()) {
String s = shortDNA.substring(positionInShort, positionInShort + 1);
if(positionInShort + positionInLong + 1 > longDNA.length()) {
break;
}
String l = longDNA.substring(positionInShort + positionInLong, positionInShort + positionInLong + 1);
if(canConnect(s, l)) {
positionInShort++;
if(positionInShort == shortDNA.length()) {
return positionInLong;
}
} else {
break;
}
}
positionInLong++;
if(positionInLong == longDNA.length()) {
return -1;
}
}
return -1;
}
private static String[] connections = {
"AT",
"TA",
"GC",
"CG"
};
private static boolean canConnect(String s, String l) {
if(Arrays.asList(connections).contains((s+l).toUpperCase())) {
return true;
} else {
return false;
}
}
}
I finally changed something with the k as Faraz had mentioned above to make sure the charAt does not get used when k overrides the length of the string and the program worked marvelously!
The code was changed to the following:
int tries=0;
int pos=-1;
int k;
for (int i=0; i<longDNA.length(); i++) {
tries=0;
k=i;
for (int j=0; j<shortDNA.length(); j++) {
if (k<longDNA.length()) {
char s=shortDNA.charAt(j);
char l=longDNA.charAt(k);
if ((s=='A' && l=='T') || (s=='T' && l=='A') || (s=='G' && l=='C') || (s=='C' && l=='G')) {
tries+=1;
k+=1;
}
}
}
if (tries==shortDNA.length()) {
pos=i;
break;
}
}
I am not sure how aesthetically pleasing or correct this excerpt is but - it completely solved my problem, and just 2 minutes before the deadline! :)
A huge thanks to all of you for spending some time to help me!!
I need a byte generator that would generate values from Byte.MIN_VALUE to Byte.MAX_VALUE. When it reaches MAX_VALUE, it should start over again from MIN_VALUE.
I have written the code using AtomicInteger (see below); however, the code does not seem to behave properly if accessed concurrently and if made artificially slow with Thread.sleep() (if no sleeping, it runs fine; however, I suspect it is just too fast for concurrency problems to show up).
The code (with some added debug code):
public class ByteGenerator {
private static final int INITIAL_VALUE = Byte.MIN_VALUE-1;
private AtomicInteger counter = new AtomicInteger(INITIAL_VALUE);
private AtomicInteger resetCounter = new AtomicInteger(0);
private boolean isSlow = false;
private long startTime;
public byte nextValue() {
int next = counter.incrementAndGet();
//if (isSlow) slowDown(5);
if (next > Byte.MAX_VALUE) {
synchronized(counter) {
int i = counter.get();
//if value is still larger than max byte value, we reset it
if (i > Byte.MAX_VALUE) {
counter.set(INITIAL_VALUE);
resetCounter.incrementAndGet();
if (isSlow) slowDownAndLog(10, "resetting");
} else {
if (isSlow) slowDownAndLog(1, "missed");
}
next = counter.incrementAndGet();
}
}
return (byte) next;
}
private void slowDown(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
}
}
private void slowDownAndLog(long millis, String msg) {
slowDown(millis);
System.out.println(resetCounter + " "
+ (System.currentTimeMillis()-startTime) + " "
+ Thread.currentThread().getName() + ": " + msg);
}
public void setSlow(boolean isSlow) {
this.isSlow = isSlow;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
}
And, the test:
public class ByteGeneratorTest {
#Test
public void testGenerate() throws Exception {
ByteGenerator g = new ByteGenerator();
for (int n = 0; n < 10; n++) {
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
assertEquals(i, g.nextValue());
}
}
}
#Test
public void testGenerateMultiThreaded() throws Exception {
final ByteGenerator g = new ByteGenerator();
g.setSlow(true);
final AtomicInteger[] counters = new AtomicInteger[Byte.MAX_VALUE-Byte.MIN_VALUE+1];
for (int i = 0; i < counters.length; i++) {
counters[i] = new AtomicInteger(0);
}
Thread[] threads = new Thread[100];
final CountDownLatch latch = new CountDownLatch(threads.length);
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
try {
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
byte value = g.nextValue();
counters[value-Byte.MIN_VALUE].incrementAndGet();
}
} finally {
latch.countDown();
}
}
}, "generator-client-" + i);
threads[i].setDaemon(true);
}
g.setStartTime(System.currentTimeMillis());
for (int i = 0; i < threads.length; i++) {
threads[i].start();
}
latch.await();
for (int i = 0; i < counters.length; i++) {
System.out.println("value #" + (i+Byte.MIN_VALUE) + ": " + counters[i].get());
}
//print out the number of hits for each value
for (int i = 0; i < counters.length; i++) {
assertEquals("value #" + (i+Byte.MIN_VALUE), threads.length, counters[i].get());
}
}
}
The result on my 2-core machine is that value #-128 gets 146 hits (all of them should get 100 hits equally as we have 100 threads).
If anyone has any ideas, what's wrong with this code, I'm all ears/eyes.
UPDATE: for those who are in a hurry and do not want to scroll down, the correct (and shortest and most elegant) way to solve this in Java would be like this:
public byte nextValue() {
return (byte) counter.incrementAndGet();
}
Thanks, Heinz!
Initially, Java stored all fields as 4 or 8 byte values, even short and byte. Operations on the fields would simply do bit masking to shrink the bytes. Thus we could very easily do this:
public byte nextValue() {
return (byte) counter.incrementAndGet();
}
Fun little puzzle, thanks Neeme :-)
You make the decision to incrementAndGet() based on a old value of counter.get(). The value of the counter can reach MAX_VALUE again before you do the incrementAndGet() operation on the counter.
if (next > Byte.MAX_VALUE) {
synchronized(counter) {
int i = counter.get(); //here You make sure the the counter is not over the MAX_VALUE
if (i > Byte.MAX_VALUE) {
counter.set(INITIAL_VALUE);
resetCounter.incrementAndGet();
if (isSlow) slowDownAndLog(10, "resetting");
} else {
if (isSlow) slowDownAndLog(1, "missed"); //the counter can reach MAX_VALUE again if you wait here long enough
}
next = counter.incrementAndGet(); //here you increment on return the counter that can reach >MAX_VALUE in the meantime
}
}
To make it work one has to make sure the no decisions are made on stale info. Either reset the counter or return the old value.
public byte nextValue() {
int next = counter.incrementAndGet();
if (next > Byte.MAX_VALUE) {
synchronized(counter) {
next = counter.incrementAndGet();
//if value is still larger than max byte value, we reset it
if (next > Byte.MAX_VALUE) {
counter.set(INITIAL_VALUE + 1);
next = INITIAL_VALUE + 1;
resetCounter.incrementAndGet();
if (isSlow) slowDownAndLog(10, "resetting");
} else {
if (isSlow) slowDownAndLog(1, "missed");
}
}
}
return (byte) next;
}
Your synchronized block contains only the if body. It should wrap whole method including if statement itself. Or just make your method nextValue synchronized. BTW in this case you do not need Atomic variables at all.
I hope this will work for you. Try to use Atomic variables only if your really need highest performance code, i.e. synchronized statement bothers you. IMHO in most cases it does not.
If I understand you correctly, you care that the results of nextValue are in the range of Byte.MIN_VALUE and Byte.MAX_VALUE and you don't care about the value stored in the counter.
Then you can map integers on bytes such that you required enumeration behavior is exposed:
private static final int VALUE_RANGE = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
private final AtomicInteger counter = new AtomicInteger(0);
public byte nextValue() {
return (byte) (counter.incrementAndGet() % VALUE_RANGE + Byte.MIN_VALUE - 1);
}
Beware, this is untested code. But the idea should work.
I coded up the following version of nextValue using compareAndSet which is designed to be used in a non-synchronized block. It passed your unit tests:
Oh, and I introduced new constants for MIN_VALUE and MAX_VALUE but you can ignore those if you prefer.
static final int LOWEST_VALUE = Byte.MIN_VALUE;
static final int HIGHEST_VALUE = Byte.MAX_VALUE;
private AtomicInteger counter = new AtomicInteger(LOWEST_VALUE - 1);
private AtomicInteger resetCounter = new AtomicInteger(0);
public byte nextValue() {
int oldValue;
int newValue;
do {
oldValue = counter.get();
if (oldValue >= HIGHEST_VALUE) {
newValue = LOWEST_VALUE;
resetCounter.incrementAndGet();
if (isSlow) slowDownAndLog(10, "resetting");
} else {
newValue = oldValue + 1;
if (isSlow) slowDownAndLog(1, "missed");
}
} while (!counter.compareAndSet(oldValue, newValue));
return (byte) newValue;
}
compareAndSet() works in conjunction with get() to manage concurrency.
At the start of your critical section, you perform a get() to retrieve the old value. You then perform some function dependent only on the old value to compute a new value. Then you use compareAndSet() to set the new value. If the AtomicInteger is no longer equal to the old value at the time compareAndSet() is executed (because of concurrent activity), it fails and you must start over.
If you have an extreme amount of concurrency and the computation time is long, it is conceivable that the compareAndSet() may fail many times before succeeding and it may be worth gathering statistics on that if concerns you.
I'm not suggesting that this is a better or worse approach than a simple synchronized block as others have suggested, but I personally would probably use a synchronized block for simplicity.
EDIT: I'll answer your actual question "Why doesn't mine work?"
Your code has:
int next = counter.incrementAndGet();
if (next > Byte.MAX_VALUE) {
As these two lines are not protected by a synchronized block, multiple threads can execute them concurrently and all obtain values of next > Byte.MAX_VALUE. All of them will then drop through into the synchronized block and set counter back to INITIAL_VALUE (one after another as they wait for each other).
Over the years, there has been a huge amount written over the pitfalls of trying to get a performance tweak by not synchronizing when it doesn't seem necessary. For example, see Double Checked Locking
Notwithstanding that Heinz Kabutz is the clean answer to the specific question, ye olde Java SE 8 [March 2014] added AtomicIntger.updateAndGet (and friends). This leads to a more general solution if circumstances required:
public class ByteGenerator {
private static final int MIN = Byte.MIN_VALUE;
private static final int MAX = Byte.MAX_VALUE;
private final AtomicInteger counter = new AtomicInteger(MIN);
public byte nextValue() {
return (byte)counter.getAndUpdate(ByteGenerator::update);
}
private static int update(int old) {
return old==MAX ? MIN : old+1;
}
}