Concat new characters to StringBuilder object atomically - java

My problem is:
I have class:
public class AtomicStringBuilder {
private final AtomicReference<StringBuilder> sbRef;
}
I need to add new characters to StringBuilder concurrently and atomically. But problem is, only last 128 characters should be in this object. I can't use StringBuffer, because operation should be non-blocking.
So,there are two operations:
First: check if StringBuilder already has 128 chars.
Second: if it has not -> add new char, if it has -> delete first char and add new char.
Is there a way to make this two or three operations atomic?
I made this method, but it doesn't work:
public void append(String string) {
this.sbRef.getAndUpdate(ref -> {
if (ref.length() < 128) {
ref.append(string);
} else {
ref.append(string).delete(0, ref.length() - 128);
}
return ref;
});
}
For testing I created this method:
public void test() {
AtomicStringBuilder atomicStringBuilder = new AtomicStringBuilder();
Random random = new Random();
Stream<Integer> infiniteStream = Stream.iterate(0, i -> random.nextInt(10));
infiniteStream.parallel()
.limit(100000)
.forEach(integer -> atomicStringBuilder.append(String.valueOf(integer)));
assertEquals(128, atomicStringBuilder.getSb().get().length());
}
This is not a real prolem, I can change AtomicReference with anything else which will work. The task is to create operation that will be lock-free and without race conditions

Here's a solution with immutable Strings.
If you use AtomicReference you need to return a new reference rather than mutating the object the reference points to. Atomically comparing the current and expected value of the reference is the only way to know that it hasn't been updated by another thread.
getAndUpdate does this:
get the current reference
apply the lambda to the reference, getting a new reference
if the current reference hasn't changed, atomically set it to the new reference, otherwise go back to 1.
public class App {
static class AtomicStringBuilder {
public final AtomicInteger counter = new AtomicInteger();
public final AtomicReference<String> sbRef = new AtomicReference<>("");
public void append(String string) {
this.sbRef.getAndUpdate(ref -> {
counter.getAndIncrement();
if (ref.length() < 128) {
return ref + string;
} else {
String s = ref + string;
return s.substring(s.length() - 128);
}
});
}
}
static void test() {
AtomicStringBuilder atomicStringBuilder = new AtomicStringBuilder();
Random random = new Random();
Stream<Integer> infiniteStream = Stream.iterate(0, i -> random.nextInt(10));
infiniteStream.parallel()
.limit(100000)
.forEach(integer -> atomicStringBuilder.append(String.valueOf(integer)));
if (128 != atomicStringBuilder.sbRef.get().length()) {
System.out.println("failed ");
}
System.out.println(atomicStringBuilder.sbRef.get());
System.out.println(atomicStringBuilder.counter.get());
}
public static void main(String[] args) {
test();
}
}
I've added a counter to the lambda. The value it shows after running this program will be more than 100,000, because concurrent updates forced retries.

Related

Returns in java function parameters in easy way [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 4 years ago.
I can't get return in function's aaa parameters a and b like:
public static void aaa( boolean a , Integer b)
{
a=true;
b =2;
}
public static void main(String[] args)
{
boolean a=false;
int b=1;
aaa(a,b);
lg.info("{} {}",a,b );
}
I will get same false 1 in output.
Each time when I need to have more than one return in function I must create class-holder:
public static class BoolAndIntHolder
{
boolean a ;
Integer b ;
}
public static void aa(BoolAndIntHolder s)
{
s.a =true;
s.b =2;
}
public static void main(String[] args)
{
BoolAndIntHolder s= new BoolAndIntHolder();
s.a = false;
s.b=1;
aa(s);
lg.info("{} {}",s.a,s.b );
}
This gives true 2 in output as wanted.
But this looks so horrible each time to create different class holders. Is here any hacks how to write code in such situation in less dramatic way?
UPD
Looks like I must use data class'es in order to return several values since it is less complicated way. Solution bellow looks ugly for me. Is it possible to solve task in more elegant way?
enum TRUE_FALSE_ERR {TRUE,FALSE,ERR};
static TRUE_FALSE_ERR aaa()
{
if (isConnected())
{
if getResult() return TRUE_FALSE_ERR.TRUE else
return TRUE_FALSE_ERR.FALSE;
} else
return TRUE_FALSE_ERR.ERR;
}
public static void main(String[] args)
{
switch (aaa()) {
case ERR:
lg.info("ERR");
break;
case TRUE:
lg.info("TRUE");
break;
case FALSE:
lg.info("FALSE");
break;
default : lg.info("default");
}
}
If two primitives are not inter-connected, you should (in theory) calculate them in separate methods.
If they are inter-connected, it makes sense to encapsulate them in a data class (which can later be extended to have behavior that is related to these primitives)
Alternative 1: Lambda callback
You could make the method call the caller back with the results.
interface Callback {
void accept(boolean b, int i);
}
public static void aaa(Callback callback) {
callback.accept(true, 2);
}
public static void main(String... args) {
aaa((a, b) -> System.out.println(a + " " + b));
}
Prints:
true 2
Alternative 2: AtomicBoolean and AtomicInteger
You could pass in AtomicBoolean and AtomicInteger objects. These can be set by the function and then read by the main method.
public static void bbb(AtomicBoolean b, AtomicInteger i) {
b.set(true);
i.set(2);
}
public static void main(String... args) {
AtomicBoolean atomicBoolean = new AtomicBoolean(false);
AtomicInteger atomicInteger = new AtomicInteger(0);
bbb(atomicBoolean, atomicInteger);
System.out.println(atomicBoolean.get() + " " + atomicInteger.get());
}
Prints:
true 2
This kind of thing is a bit of hack though.
Alternative 3: Find the right abstraction
If you want to return two things from a function, it would be better to pull out a well-named class to represent them. The right abstraction will make your code easier to understand in the future. Hint: BoolAndIntHolder is not a good abstraction. You need to ask yourself "what does it represent in the language of the domain?"
Alternative 4: Split into two functions
In my experience, in most of the cases where I've wanted to return two results, I've found it's better to write two separate functions. It may be less "efficient" but usually produces code that is easier to understand and easier to modify. It decouples the two concepts. I don't know what your situation is though, so it's hard to know whether this applies here.
That's how Java is designed, you can't return more than one value. Most of the time a wrapper object is used like you tried, if you intend to reuse created object in many places then it's a good approach but if you want to use this object only in one place then an easy alternative since Java 9 is to use Map in one line:
public static Map<String, Object> aa(){
...
return new Map.of("a", true, "b", 2);
Ff returned arguments are of different type then you have to cast, but if you just want to print objects and they have toString method overridden then casting isn't necessary:
lg.info("{} {}", map.get("a"), map.get("b") );
You can use Java Observable values, such as:
public static void main(String[] args) {
SimpleBooleanProperty a = new SimpleBooleanProperty(false);
SimpleIntegerProperty b = new SimpleIntegerProperty(1);
changeValue(a, b);
System.out.println(a.getValue() + " :: " + b.getValue());
}
public static void changeValue(SimpleBooleanProperty a, SimpleIntegerProperty b) {
a.setValue(true);
b.setValue(2);
}
With this methodology, you can use 'a' and 'b' to be notified when other object is modified, for example:
public static void main(String[] args) {
SimpleBooleanProperty a = new SimpleBooleanProperty(false);
SimpleBooleanProperty aNotifier = new SimpleBooleanProperty();
a.bind(aNotifier);
SimpleIntegerProperty b = new SimpleIntegerProperty(1);
SimpleIntegerProperty bNotifier = new SimpleIntegerProperty();
b.bind(bNotifier);
changeValue(aNotifier, bNotifier);
System.out.println(a.getValue() + " :: " + b.getValue());
}
public static void changeValue(SimpleBooleanProperty a, SimpleIntegerProperty b) {
a.setValue(true);
b.setValue(2);
}

How to make this piece of code thread safe?

This code is part of within a method. The code go through two lists using two for loop. I want to see whether there is a possibility of using multi thread to speed up this process for the two loops. My concern is how to make it thread safe.
EDITTED: more complete code
static class Similarity {
double similarity;
String seedWord;
String candidateWord;
public Similarity(double similarity, String seedWord, String candidateWord) {
this.similarity = similarity;
this.seedWord = seedWord;
this.candidateWord = candidateWord;
}
public double getSimilarity() {
return similarity;
}
public String getSeedWord() {
return seedWord;
}
public String getCandidateWord() {
return candidateWord;
}
}
static class SimilarityTask implements Callable<Similarity> {
Word2Vec vectors;
String seedWord;
String candidateWord;
Collection<String> label1;
Collection<String> label2;
public SimilarityTask(Word2Vec vectors, String seedWord, String candidateWord, Collection<String> label1, Collection<String> label2) {
this.vectors = vectors;
this.seedWord = seedWord;
this.candidateWord = candidateWord;
this.label1 = label1;
this.label2 = label2;
}
#Override
public Similarity call() {
double similarity = cosineSimForSentence(vectors, label1, label2);
return new Similarity(similarity, seedWord, candidateWord);
}
}
Now, is this 'compute' thread safe? There are 3 variables involved:
1) vectors;
2) toeknizerFactory;
3) similarities;
public static void compute() throws Exception {
File modelFile = new File("sim.bin");
Word2Vec vectors = WordVectorSerializer.readWord2VecModel(modelFile);
TokenizerFactory tokenizerFactory = new TokenizerFactory()
List<String> seedList = loadSeeds();
List<String> candidateList = loadCandidates();
log.info("Computing similarity: ");
ExecutorService POOL = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<Future<Similarity>> tasks = new ArrayList<>();
int totalCount=0;
for (String seed : seedList) {
Collection<String> label1 = getTokens(seed.trim(), tokenizerFactory);
if (label1.isEmpty()) {
continue;
}
for (String candidate : candidateList) {
Collection<String> label2 = getTokens(candidate.trim(), tokenizerFactory);
if (label2.isEmpty()) {
continue;
}
Callable<Similarity> callable = new SimilarityTask(vectors, seed, candidate, label1, label2);
tasks.add(POOL.submit(callable));
log.info("TotalCount:" + (++totalCount));
}
}
Map<String, Set<String>> similarities = new HashMap<>();
int validCount = 0;
for (Future<Similarity> task : tasks) {
Similarity simi = task.get();
Double similarity = simi.getSimilarity();
String seedWord = simi.getSeedWord();
String candidateWord = simi.getCandidateWord();
Set<String> similarityWords = similarities.get(seedWord);
if (similarity >= 0.85) {
if (similarityWords == null) {
similarityWords = new HashSet<>();
}
similarityWords.add(candidateWord);
log.info(seedWord + " " + similarity + " " + candidateWord);
log.info("ValidCount: " + (++validCount));
}
if (similarityWords != null) {
similarities.put(seedWord, similarityWords);
}
}
}
Added one more relevant method, which is used by the call() method:
public static double cosineSimForSentence(Word2Vec vectors, Collection<String> label1, Collection<String> label2) {
try {
return Transforms.cosineSim(vectors.getWordVectorsMean(label1), vector.getWordVectorsMean(label2));
} catch (Exception e) {
log.warn("OOV: " + label1.toString() + " " + label2.toString());
//e.getMessage();
//e.printStackTrace();
return 0.0;
}
}
(Answer updated for changed question.)
In general you should profile the code before attempting to optimise it, particularly if it is quite complex.
For threading you need to identify which mutable state is shared between threads. Ideally as much as that as possible before resorting to locks and concurrent data structures. Mutable state that is contained within one thread isn't a problem as such. Immutables are great.
I assume nothing passed to your task gets modified. It's tricky to tell. final on fields is a good idea. Collections can be placed in unmodifiable wrappers, though that doesn't stop them being modified via other references and does now show itself in static types.
Assuming you don't break up the inner loop, the only shared mutable state appears to be similarities and the values it contains.
You may or may not find you still end up doing too much serially and need to change similarities to become concurrent
ConcurrentMap<String, Set<String>> similarities = new ConcurrentHashMap<>();
The get and put of similarities will need to be thread-safe. I suggest always creating the Set.
Set<String> similarityWords = similarities.getOrDefault(seed, new HashSet<>());
or
Set<String> similarityWords = similarities.computeIfAbsent(seed, key -> new HashSet<>());
You could use a thread-safe Set (for instance with Collections.synchronizedSet), but I suggest holding a relevant lock for the entire inner loop.
synchronized (similarityWords) {
...
}
If you wanted to create similarityWords lazily then it would be "more fun".

Add null-like value to String in Java

I am writing test method like setTask(Task task). And Task object has several fields, e.g.
public String vehicle;
Method setTask should be used in different test-cases, so I'd like to have an options for this field to accept values:
null - the method should not do anything in this particulare case;
some string value - e.g. "", "Hello, World!", "Iso Isetta", ...
random - a value that indicates (as well as null indicates "no changes") that a random value should be selected for a drop-down list corresponding to this field.
So what can I do to make String to be SpecialString which could accept values null, random & some string value? (BTW: I don't want to set it to string value "RANDOM", and chech whether the value is equal to "RANDOM"-string)
UPDATE: I don't mean random like random value from a set of values, I mean random as well as null and this is for setTask() to handle random (select random from drop-down), and not to pass a random string from a set of values.
Pseudocode:
Task task = new Task();
task.vehicle = random; // as well as null
setTask(task)
in setTask(Task task):
if (task.vehicle == null) {
//skip
} else if (task.vehicle == random) {
// get possible values from drop-down list
// select one of them
} else {
// select value from drop-down list which is equal to task.vehicle
}
Don't assign a fixed String but use a Supplier<String> which can generate a String dynamically:
public Supplier<String> vehicleSupplier;
This, you can assign a generator function as you request:
static Supplier<String> nullSupplier () { return () -> null; }
static Supplier<String> fixedValueSupplier (String value) { return () -> value; }
static Supplier<String> randomSupplier (String... values) {
int index = ThreadLocalRandom.current().nextInt(values.length) -1;
return index > 0 && index < values.length ? values[index] : null;
}
In use, this looks like:
task.setVehicleSupplier(nullSupplier()); // or
task.setVehicleSupplier(fixedValueSupplier("value")); // or
task.setVehicleSupplier(randomSupplier("", "Hello, World!", "Iso Isetta"));
and you can get the String by
String value = task.vehicleSupplier().get();
or hide the implementation in a getter function
class Task {
// ...
private Supplier<String> vehicleSupplier;
public void setVehicleSupplier(Supplier<String> s) {
vehicleSupplier = s;
}
public String getVehicle() {
return vehicleSupplier != null ? vehicleSupplier.get() : null;
}
// ...
}
What you may want to do is to create an object that wraps a string as well as some information about whether or not it's a special value. Something along the lines of...
public class Special<T> {
public enum Type {
NOTHING, RANDOM, SPECIFIC
}
private final Type type;
private final T specificValue;
public Special(Type type, T specificValue) {
this.type = type;
this.specificValue = specificValue;
}
public Type getType() {
return type;
}
public T getSpecificValue() {
if (type != SPECIFIC) {
throw new IllegalStateException("Value is not specific");
}
return specificValue;
}
}
The class above could be used like so:
Special<String> a = new Special<>(Special.Type.NOTHING, null);
Special<String> b = new Special<>(Special.Type.SPECIFIC, "Hello");
if (b.getType() == Special.Type.RANDOM) {
// do something
}else if (b.getType() == Special.Type.SPECIFIC) {
String val = b.getSpecificValue();
// do something else
}
A slightly more polished variant of the thing above is probably the best way, but there is a way, a much uglier way, to do it using nothing but a String field.
What you could do is to have a "magical" string instance that behaves differently from all other string instances, despite having the same value. This would be done by having something like
static final String SPECIAL_VALUE_RANDOM = new String("random");
Note the use of the String constructor, which ensures that the string becomes a unique, non-interned instance. You can then say if (vehicle == SPECIAL_VALUE_RANDOM) { ... } (note the use of == instead of .equals()) to check if that specific instance (rather than any other string that says "random") was used.
Again, this is not a particularly good way of doing this, especially if you intend to do this more than once ever. I would strongly suggest something closer to the first way.

Implemented Iterable hands wrong size back

I'm new to this site, so please feel free to correct me if there's anything wrong about my question or the style of the question.
I need to implement the Iterable Interface in my ShareCollection class, so that I can iterate over all the shares in this class. When I'm testing my class with the sample data it always hands back '0' as size, even though there are (in my example) two shares in my collection.
Here's the code of the class + one sample method which hands back an error:
public class ShareCollection implements Iterable<Share>{
private HashSet<Share> shares;
public ShareCollection() {
this.shares = new HashSet<Share>();
}
public ShareCollection(Collection<Share> shares) {
for (Share s : shares) {
HashSet<Share> checkSet = new HashSet<Share>(shares);
checkSet.remove(s);
if (checkSet.contains(s)) {
throw new IllegalArgumentException("There can't be two shares with the same name!");
}
}
this.shares = new HashSet<Share>(shares);
}
public boolean add(Share share) {
if (share == null) {
throw new NullPointerException("share isnt allowed to be null!");
}
return shares.add(share);
}
#Override
public Iterator<Share> iterator() {
return new HashSet<Share>(shares).iterator();
}
}
Here's the main method with the sample data I'm using:
public static void main(String[] args) {
Share s1 = new Share("s1", new ArrayList<>());
Share s2 = new Share("s2", new ArrayList<>());
ShareCollection sc = new ShareCollection()
sc.add(s1);
sc.add(s2);
int counter = 0;
for (Share s : sc) {
counter++;
}
System.out.print("Counter: " + counter + "\n");
System.out.print("Size: " + sc.size());
}
Here's the output for the main-method:
Counter: 2
Size: 0
Here's the error for the 'add'-method:
java.lang.AssertionError: ShareCollection#size should give 1 for a collection with 1 elements.
Expected: <1>
but: was <0>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at jpp.marketanalysis.tests.data.TestShareCollection.hasElements(TestShareCollection.java:158)
at jpp.marketanalysis.tests.data.TestShareCollection.testAdd(TestShareCollection.java:55)
Thank you in advance for your answers!
Update:
Exchanged the ArrayList with a HashSet (see #SeanPatrickFloyd's first answer)
Possible error: Does your Share class override the .equals() method?
Because ArrayList.contains() delegates to .equals()
Also, I see at least two problems with your code:
An ArrayList is very bad at a .contains() lookup (O(n)). You should use a HashSet instead (in that case you'd need to override both .equals() and .hashCode() in your Share class), it gives you O(1) and handles the .add() method properly for you as well
The Iterator you are returning is the ArrayList's original iterator, which makes your code vulnerable in several ways, including ConcurrentModificationException if you add something while iterating, but also mutation, if someone calls .remove() on the iterator. I'd suggest you make a defensive copy of the collection and use that iterator.
Here's your code rewritten accordingly:
public class ShareCollection implements Iterable<Share>{
private final Set<Share> shares;
public ShareCollection() {
this.shares = new HashSet<>();
}
public ShareCollection(Collection<Share> shares) {
this.shares = new HashSet<>(shares);
}
public boolean add(Share share) {
if (share == null) {
throw new NullPointerException("share isnt allowed to be null!");
}
return shares.add(share);
}
#Override
public Iterator<Share> iterator() {
return new HashSet<>(shares).iterator();
}
}

Initialize Runnable Array of Lambdas(with string arg and returns a boolean) and Call Index

I was able to get this working with lambda's returning void and taking in 0 args using a hash table, see here -> Create lambda two dimensional array
Now, I'm trying to create a Runnable[] array, with lambda's in the index, and each lambda takes a String argument and returns a boolean.
Here is the code...
public class testLambdaWithPrimitiveType {
private final String[] numArray = {"One", "Two", "Three"};
private boolean numFound = false;
testLambdaWithPrimitiveType(String num){
setNumFound(num);
}
private void setNumFound(String num){
Runnable[] runnableNumArray = {
() -> isStringOne(num),
() -> isStringTwo(num),
() -> isStringThree(num)
};
for (int numChecked = 0; numChecked < runnableNumArray.length; numChecked++){
if (runnableNumArray[numChecked].run(num)){
this.numFound = true;
}
}
}
private boolean isNumFound(){return this.numFound;}
private boolean isStringOne(String num){
return num.equals(numArray[0]);
}
private boolean isStringTwo(String num){
return num.equals(numArray[1]);
}
private boolean isStringThree(String num){
return num.equals(numArray[2]);
}
public static void main(String[] args) {
testLambdaWithPrimitiveType objectOne = new testLambdaWithPrimitiveType("One");
testLambdaWithPrimitiveType objectTwo = new testLambdaWithPrimitiveType("Two");
testLambdaWithPrimitiveType objectThree = new testLambdaWithPrimitiveType("Three");
testLambdaWithPrimitiveType objectFour = new testLambdaWithPrimitiveType("Four");
System.out.println(objectFour.isNumFound()); // false
System.out.println(objectThree.isNumFound()); // true
System.out.println(objectTwo.isNumFound()); // true
System.out.println(objectOne.isNumFound()); // true
}
}
It looks like the array gets initialized correctly, but when I try to call on the index if (runnableNumArray[numChecked].run(num)){, I get a compile error. Any idea why this is happening?
That is because Runnable has method void run(), with no parameters, and you're trying to call run(num). Since num has already been applied from the setNumFound() parameter, just call using run().
Of course, that leads to second error, i.e. method returns void, so the if (run()) doesn't work.
Seems you might want a method boolean xxx(String), so replace Runnable with Predicate<String>, and you can call it using test(num) instead of run().
That then leads to compilation error Cannot create a generic array of Predicate<String>, so you have to replace the array with a List.
You can then use method references instead.
private void setNumFound(String num){
List<Predicate<String>> runnableNumList = Arrays.asList(
this::isStringOne,
this::isStringTwo,
this::isStringThree
);
for (Predicate<String> runnableNum : runnableNumList){
if (runnableNum.test(num)){
this.numFound = true;
}
}
}
In the Java Language, Runnable instances cannot have parameters, lambdas which do have parameters are Callable instances instead. In other words, your question is inaccurate... you cannot create Runnable array that takes parameters, even though the compiler (wrongly) allows you to.
The error is that the Runnable interface has a run method with the signature,
public abstract void run()
Yet you are trying pass a parameter to that run method.
runnableNumArray[numChecked].run( num )
Removing the num parameter will still give you an error. This is because the run method returns void which is nothing (look again at the signature) but if statements require a boolean value to evaluate.
I am not sure what you are trying to achieve with this Array of lambdas. If you give me more info, I might be able to correct your code. As it stands though, it is unclear what you are expecting the Runnables to achieve.
Here is an example of using Callable instances to achieve something of what you wanted.
private void setNumFound(String num) throws Exception {
Callable[] runnableNumArray = {
() -> isStringOne( num ),
() -> isStringTwo( num ),
() -> isStringThree( num )
};
for ( int numChecked = 0; numChecked < runnableNumArray.length; numChecked++ ){
if ( ( Boolean ) runnableNumArray[numChecked].call() ){
this.numFound = true;
}
}
}
private void setNumFound(String num){
boolean[] a = new boolean[1];
Runnable[] runnableNumArray = {
() -> a[0] = isStringOne(num),
() -> a[0] = isStringTwo(num),
() -> a[0] = isStringThree(num)
};
for (Runnable r : runnableNumArray ) {
r.run();
if ( a[0] ) {
this.numFound = true;
break; }
}
}
I rewrite your method and added boolean variable as array[1]. I think, so wrong write, in general situation you will get error: "local variables referenced from a lambda expression must be final or effectively final" - but its work in Java SE 8 (build 31).

Categories

Resources