I had a class like this :
class Test
{
public static test getInstance()
{
return new test()
}
public void firstMethod()
{
//do something
}
public void secondMethod()
{
//do something
}
public void thirdMethod()
{
//do something
}
}
in the another class if we calling Test.getInstance().methodName() several times with different method, what happening?
Which one will be faster and using low memory in following codes?
Test.getInstance().firstMethod()
Test.getInstance().secondMethod()
Test.getInstance().thirdMethod()
or
Test test = Test.getInstance();
test.firstMethod();
test.secondMethod();
test.thirdMethod();
Test.getInstance().firstMethod()
Test.getInstance().secondMethod()
Test.getInstance().thirdMethod()
This will create three different instances of the Test class and call a method on each.
Test test = Test.getInstance();
test.firstMethod();
test.secondMethod();
test.thirdMethod();
Will create only one instance and invoke the three methods on that instance.
So it's a completely different behavior to begin with. Obviously, since the first creates three objects, then it should take more heap space.
If you're intending to implement a singleton class, however, both are equivalent.
Every time you call getInstance the system has to allocate heap storage for a Test object and initialize it.
Furthermore, somewhere down the line the system will have to garbage-collect all those extra Test objects. With a copying collector the overhead per object is minimal, but there is some -- if for no other reason than you're causing GC to occur more often.
class Test
{
public static Test getInstance()
{
return new Test();
}
public void firstMethod()
{
// do something
}
public void secondMethod()
{
// do something
}
public void thirdMethod()
{
// do something
}
}
public class Blah
{
public static void main(String[] args)
{
int i = 0;
long start = System.nanoTime();
Test t = new Test();
for (; i < 100000; i++)
{
t.firstMethod();
}
long stop = System.nanoTime();
System.out.println(stop - start);
i = 0;
start = System.nanoTime();
for (; i < 100000; i++)
{
Test.getInstance().firstMethod();
}
stop = System.nanoTime();
System.out.println(stop - start);
}
}
output:
~3486938
~4894574
Creating single instance with new Test() proved to be consistently faster by about 30%.
Memory calculations are harder due to disability to do it in one run. However if we run only the first loop (changing what's inside) and use:
Runtime runtime = Runtime.getRuntime();
long memory = runtime.totalMemory() - runtime.freeMemory();
just before printing. In two separate runs we can determine the difference: ~671200 or ~1342472 (seemed to change between runs rather randomly with no clear influence on runtime) for new Test() and ~2389288 (no big differences this time) for getInstance() in 100000 iterations. Again clear victory to single instance
Related
I'm new to multithreading in general, so I still don't fully understand it. I don't get why my code is having issues. I'm trying to populate an ArrayList with the first 1000 numbers, and then sum all of them using three threads.
public class Tst extends Thread {
private static int sum = 0;
private final int MOD = 3;
private final int compare;
private static final int LIMIT = 1000;
private static ArrayList<Integer> list = new ArrayList<Integer>();
public Tst(int compare){
this.compare=compare;
}
public synchronized void populate() throws InterruptedException{
for(int i=0; i<=Tst.LIMIT; i++){
if (i%this.MOD == this.compare){
list.add(i);
}
}
}
public synchronized void sum() throws InterruptedException{
for (Integer ger : list){
if (ger%MOD == this.compare){
sum+=ger;
}
}
}
#Override
public void run(){
try {
populate();
sum();
System.out.println(sum);
} catch (InterruptedException ex) {
Logger.getLogger(Tst.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
Tst tst1 = new Tst(0);
tst1.start();
Tst tst2 = new Tst(1);
tst2.start();
Tst tst3 = new Tst(2);
tst3.start();
}
}
I expected it to print "500.500", but instead it prints this:
162241
328741
Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996)
at tst.Tst.sum(Tst.java:38)
at tst.Tst.run(Tst.java:50)
BUILD SUCCESSFUL (total time: 2 seconds)
The problem is happening because your methods are synchronized in "object level", I mean, the monitor lock it uses is of a particular object (tst1,tst2,tst3). In other words, each synchronized method is using a different lock.
Change your synchronized methods to static as a first step to fix it.
while run of tst1 is counting the sum in for-each then run of tst2 might increasing the size of list. So its throwing concurrent modification exception. Using a join can help.
public static void main(String[] args) {
Tst tst1 = new Tst(0);
tst1.start();
tst1.join()
Tst tst2 = new Tst(1);
tst2.start();
tst1.join()
Tst tst3 = new Tst(2);
tst3.start();
}
You misunderstood the semantic of synchronized method, each one uses different lock object in your case, do it this way:
class SynchList {
private int sum = 0;
private final int MOD = 3;
private int compare;
private final int LIMIT = 1000;
private ArrayList<Integer> list = new ArrayList<Integer>();
public synchronized void populate( int compare) throws InterruptedException{
for(int i=0; i<=LIMIT; i++){
if (i%this.MOD == compare){
list.add(i);
}
}
}
public synchronized void sum( int compare ) throws InterruptedException{
for (Integer ger : list){
if (ger%MOD == compare){
sum+=ger;
}
System.out.println( sum );
}
}
}
class Tst extends Thread {
int compare;
SynchList synchList;
public Tst(int compare, SynchList synchList)
{
this.compare= compare;
this.synchList = synchList;
}
#Override
public void run(){
try {
synchList.populate( compare );
synchList.sum( compare );
} catch (InterruptedException ex) {
Logger.getLogger(Tst.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class Main
{
public static void main(String[] args) {
SynchList synchList = new SynchList();
Tst tst1 = new Tst( 0 , synchList );
tst1.start();
Tst tst2 = new Tst( 1, synchList );
tst2.start();
Tst tst3 = new Tst( 2, synchList );
tst3.start();
}
}
Your use of synchronized methods isn't doing what you think it's doing. The way your code is written, the methods "sum" and "populate" are protected
from running at the same time, but only on the same thread instance. That means calls to "sum" and "populate" for a single Tst object will happen one at a time,
but simultaneous calls to "sum" on different object instances will be allowed to happen concurrently.
Using synchronized on a method is equivalent to writing a method that is wrapped
with synchronized(this) { ... } around the entire method body. With three different instances created – tst1, tst2, and tst3 – this form of synchronization
doesn't guard across object instances. Instead, it guarantees that only one of populate or sum will be running at a time on a single object; any other calls to one of
those methods (on the same object instance) will wait until the prior one finishes.
Take a look at 8.4.3.6. synchronized Methods in the Java Language Specification
for more detail.
Your use of static might also not be doing what you think it's doing. Your code also shares things across all instances of the Tst thread class – namely, sum and list. Because these are defined as static,
there will be a one sum and one list. There is no thread safety in your code to guard against concurrent changes to either of those.
For example, as threads are updating
"sum" (with the line: sum+=ger), the results will be non-deterministic. That is, you will likely see different results every time you run it.
Another example of unexpected behavior with multiple threads and a single static variable is list – that will grow over time which can result in concurrency issues. The Javadoc says:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
Modifications include adding values as well as growing the backing array store. Without specifying a starting size – new ArrayList() – it will default to 10 or possibly some other relatively small number depending on which JVM version you're using. Once one thread tries to add an item that exceeds the ArrayList's capacity, it will trigger an automatic resize.
Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.
Java 7
I'm reading J. Bloch's effective Java and now I'm at the section about initializing field laziliy. He introudce the so called double-check idiom as follows:
public static void main(String[] args){
Test t = new Test();
long now = System.nanoTime();
t.getT();
long invokationTime = System.nanoTime() - now;
System.out.println(invokationTime); //Prints 3299 averagely
}
private static class Test{
private volatile Test field;
public Test getT(){
Test result = field; // <----- Note the local variable here
if(result != null){
synchronized (this) {
result = field;
if (result == null)
field = result = new Test();
}
}
return result;
}
}
DEMO
He gave the following explanation of using the local variable:
What this variable does is to
ensure that field is read only once in the common case where it’s
already initialized.
Now, let's consider the following code:
public static void main(String[] args){
Test t = new Test();
long now = System.nanoTime();
t.getT();
long invokationTime = System.nanoTime() - now;
System.out.println(invokationTime); //Prints 3101 averagely
}
private static class Test{
private volatile Test field;
public Test getT(){
if(field != null){
synchronized (this) {
if (field == null)
field = new Test();
}
}
return field;
}
}
DEMO
On my machine, the second lazy-init method is even faster. But on ideone's machine they took approximately 7985 and 10630 like J. Bloch said. So is it worth to use such local variables for optimization? As far as I coould figure out, the costs of reading and writing variables are almost equal.
So we should worry about it only if the method consist mostly of such lightweight operation, right?
It's sort of worth it because you already decided that eager loading and synchronization are both too expensive. But really, it's almost certainly not. The cases where you actually need double-checked locking code tend to be in non-locking data structures and things. Good designs for performant code tend to push that into isolated places so you're not shooting yourself in the foot every time you touch the code.
PerformanceTest1:
public class PerformanceTest1 {
public static void main(String[] args) {
boolean i = false;
if (i == false)
i = true;
System.out.println(i);
}
}
PerformanceTest2:
public class PerformanceTest2 {
public static void main(String[] args) {
boolean i = false;
i = true;
System.out.println(i);
}
}
I've been asking myself about these two possibilities, what would give the best performance. I don't know if the fact of checking if (i == false) (at PerformanceTest1) every time while(true) loop is executed would give a worse performance than just setting i = true every time the while(true) loop is executed.
Q: So, PerformanceTest1 or PerformanceTest2 would give a best performance? Why?
EDIT:
So, based on the answers, I suppose that the performance of the code below would be the same too?
public class PerformanceTest1 {
public static void main(String[] args) {
Point i;
if (i == null)
i = new Point();
}
}
public class PerformanceTest2 {
public static void main(String[] args) {
Point i;
i = new Point();
}
}
The branch predictor would just ignore the path which is executing the if inside the while after few iterations so there will be no difference, as the condition will be always false.
The CPU will keep its execution as assuming that the if is not taken and by getting a 100% prediction hit. So there will be no rollback and the two becomes basically equivalent.
Just as a side note, there's no need to have i == false, !i is enough.
There is no real difference in terms of performance between the two methods.
The first if-test will only be executed once. This is because the JVM (Java Virtual Machine) will not perform the test after a few times as i will always be true. I'm no expert on the JVM and runtime, but you might even expect the if-test to only run once.
They both will have the same performance, but I believe that the PerformanceTest1 might take up more performance, since you are doing an extra operation. it takes less performance to simply assign a value to a boolean variable, than checking if it equals to false first
Maybe this is trivial question for experienced programmers but i wonder if there is any significant performance difference (with big or very big amount of data in collection) between two difference approaches of passing variables?
I've made a tests but with rather small data structures and i don't see any significant differences. Additionally i am not sure if these differences aren't caused by interferences from other applications run in background.
Class with collection:
public class TestCollection
{
ArrayList<String[]> myTestCollection = new ArrayList<String[]>();
public TestCollection()
{
fillCollection();
}
private void fillCollection()
{
// here is fillng with big amount of data
}
public ArrayList<String[]> getI()
{
return myTestCollection;
}
}
And methods that operate on collection:
public class Test
{
static TestCollection tc = new TestCollection();
public static void main(String[] args)
{
new Test().approach_1(tc);
new Test().approach_2(tc.getI());
}
public void approach_1(TestCollection t)
{
for (int i = 0; i < tc.getI().size(); i++)
{
// some actions with collection using tc.getI().DOSOMETHING
}
}
public void approach_2(ArrayList<String[]> t)
{
for (int i = 0; i < t.size(); i++)
{
// some actions with collection using t.DOSOMETHING
}
}
}
Regards.
No, there is no real difference here.
Java passes object references to methods, not copies of the entire object. This is similar to the pass by reference concept in other languages (although we are actually passing an object reference to the called method, passed by value).
If you come from a C programming background it's important to understand this!
And, some tips - firstly, it's better practise to declare your list as List<...> rather than ArrayList<...>, like this:
List<String[]> myTestCollection = new ArrayList<String[]>();
And secondly, you can use the improved for loop on lists, like this:
// first case
for (String[] s : tc.getI()) { /* do something */ }
// second case
for (String[] s : t) { /* do something */ }
Hope this helps :)
package bankAccount;
public class CurrentAccount {
int account[];
int lastMove;
int startingBalance = 1000;
CurrentAccount() {
lastMove = 0;
account = new int[10];
}
public void deposit(int value) {
account[lastMove] = value;
lastMove++;
}
public void draw(int value) {
account[lastMove] = value;
lastMove++;
}
public int settlement() {
int result = 0;
for (int i=0; i<account.length; i++) {
result = result + account[i] + startingBalance;
System.out.println("Result = " + result);
}
return result;
}
public static void main(String args[]) {
CurrentAccount c = new CurrentAccount();
c.deposit(10);
}
}
At the moment, when I run the class, the expected System.out.println does not appear, and if I simply move public static void main(String[] args) to the top, this generates multiple red points. What is the best way for me to refactor my code so it works in the expected way?
you can have another class called Main in the file Main.java in which you can write your
public static void main(String args[])
and call
c.settlement();
in you main() to print.
Also one more advice,
in your constructor you have
account = new int[10];
which can hold only 10 ints.
in your deposit() and draw() you are not checking the account size. When the value of lastMove is more than 10 , the whole code blows up.
Hence I suggest you to use ArrayList
You never called the settlement method...
public static void main(String args[]) {
CurrentAccount c = new CurrentAccount();
c.deposit(10);
c.settlement();
}
I have the feeling that you come from some non-OOP language, like C or PHP. So some explanation:
The main method is static: that means it "exists" even when there is no object instance created, it can be thought of as if it belonged to the class instance.
on the contrary, for the other methods to "work", an instance is required.
This way the main method can be (and is actually) used as the entry point of the application
It is executed, and when it exists, (if no other threads are left running) the application terminates.
so nothing else is run that is outside of this method just by itself...
so if you don't call c.settlement(); - it won't happen...
Other notes:
Running main doesn't create an instance of the enclosing class
with new CurrentAccount(), you create an object instance, which has states it stores, and can be manipulated
be careful with arrays, they have to be taken care of, which tends to be inconvenient at times...
Why do you expect the printed output to appear? You don't actually call the settlement method, so that command is not executed.
You did not call settlement.. so nothing appears
if you add c.settlement... it is fine..
You have not called deposit() and settlement() in the main method untill you call, You cannot get expected output.