Multiply three matrices using threads in java - java

I'm trying to multiply three matrices using threads. I use a number of threads for a matrix multiplication and I should use another number of threads for multiply the result of the two matrices with the last matrices, and I would like to start the threads for the second multiplication as soon as they start having data from the first multiplication result. I'm a little stuck.
What I've tried:
public class Threads implements Runnable{
private String action;
private int range;
public Threads(String action, int range) {
this.action = action;
this.range = range +1;
}
public synchronized void run() {
int k;
int counter = 0;
int m_size = Program.m1.length;
int k_size =Program.m1[0].length;
int n_size = Program.m2[0].length;
int h_size = Program.m3[0].length;
for (int i=0; i<m_size; i++)
for (int j=0; j<n_size; j++) {
counter++;
if (counter % range == 0) {
int val1 = 0;
for (k = 0; k < k_size; k++) {
Program.result[i][j] += Program.m1[i][k] * Program.m2[k][j];
// int val1 =0;
for (int h=0; h<h_size; h++){
val1 += Program.result[i][h] * Program.m3[h][j];
}
}
Program.result_matrix[i][j] = val1; //here run error
}
}
}
public class Program {
private final static Random rand = new Random();
public static int[][] m1 = new int[][]{};
public static int[][] m2 = new int[][]{};
public static int[][] m3 = new int[][]{};
public static int[][] result = new int[][]{};
public static int[][] result_matrix = new int[][]{};
public static void generate(String action, int number_of_threads) throws InterruptedException {
List<Thread> all_threads = new ArrayList<>();
for (int th = 0; th < number_of_threads; th++) {
Thread t = new Thread(new Threads(action, th));
all_threads.add(t);
t.start();
}
for (Thread t : all_threads) {
t.join();
}
}
public static void main(String[] args) throws Exception {
{ //here i m reading the matrices
generate(action, number_of_threads);
print_result_matrix();
public static void print_result_matrix() {
for (int i = 0; i < result_matrix.length; i++) {
for (int j = 0; j < result_matrix[0].length; j++)
System.out.print(result_matrix[i][j] + " ");
System.out.println();
}
}
When I run this program I got an error after setting the matrices rows and columns and gives me error at line //look at code.
Anyway some ideas?I know that my code doesn't have a logic in run() method at the end but I really don't know how to achieve this.
Any ideas?
Stacktrace:
Exception in thread "Thread-0" Exception in thread "Thread-1 java.lang.ArrayIndexOutOfBoundsException: 0
at Threads.run(Threads.java:43)
at java.lang.Thread.run(Thread.java:745) java.lang.ArrayIndexOutOfBoundsException: 0
at Threads.run(Threads.java:43)
at java.lang.Thread.run(Thread.java:745)

You need to initialize result matrices' sizes:
public static int[][] result = new int[m1.length][m2[0].length];
public static int[][] result_matrix = new int[result.length][m3[0].length];
Of course, this should be done after m1, m2 and m3 are filled with data.

Related

Passing a 2d array to a class through multithreading

My program creates a class "MyArray"
class MyArray{
int[][] arr={{14,15,16},{11,12,13}};
}
And another class "Add_Thread"
class Add_Thread implements Runnable {
private final Matrix RES;
int row;
Thread t;
MyArray arr=new MyArray();
public Add_Thread(Matrix RES,int row) {
this.RES = RES;
t = new Thread(this);
t.start();
this.row = row;
}
public void run() {
synchronized(arr){
for (int i = 0; i < arr.arr[0].length; i++) {
RES.push(arr.arr[row][i]);
}
}
}
}
which takes value from "MyArray" and pushes it to another class "Matrix"
class Matrix {
final int[][] res_matrix;
int i = 0;
int j = 0;
private int k = 0;
private int l = 0;
public Matrix(int i, int j) {
this.i = i;
this.j = j;
res_matrix = new int[i][j];
}
public synchronized void push(int element) {
int pos1 = k;
int pos2 = l;
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(ResultantMatrix.class.getName()).log(Level.SEVERE, null, ex);
}
res_matrix[pos1][pos2] = element;
k++;
l++;
}
}
it stores the value and send it to the main() function
public class Array_demo {
public static void main(String[] args) {
Matrix res = new Matrix(2, 3);
Add_Thread add=new Add_Thread(res, 0);
Add_Thread add2=new Add_Thread(res, 1);
for(int i=0;i<res.res_matrix.length;i++)
{
for(int j=0;j<res.res_matrix[0].length;j++)
{
System.out.print(res.res_matrix[i][j]+" ");
}
System.out.println("");
}
}
}
But i'm getting error in void push() method and res_matrix[pos1][pos2]=element. I'm new to thread so it would be great if my errors are broadly explained.
Output
0 0 0
0 0 0
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 2
at threading.Matrix.push(Push.java:34)
at threading.Add_Thread.run(Push.java:58)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 2
at threading.Matrix.push(Push.java:34)
at threading.Add_Thread.run(Push.java:58)
at java.lang.Thread.run(Thread.java:745)
The main problem is that the code:
for (int i = 0; i < arr.arr[0].length; i++) {...}
produces 3 loops, and in each loop you call Matrix.push(...), so push is called three times.
In the push method, you increase the index k at every call; it starts with 0, after the first call is 1, after the second call is 2.
When you call push the third time, k holds the value of 2 and since it is assigned to the variable pos1, when you call:
res_matrix[pos1][pos2] = element;
you get the error:
java.lang.ArrayIndexOutOfBoundsException: 2
because the res_matrix array has dimension 2x3.

Sort/ Merge arrays using multi threading

I'm trying to learn multi-threading but cant get the hang of it. I've an example here.
The idea is to use two threads to sort the two arrays a and b and use another thread to merge the sorted arrays to array c.
This is my code. I tried it with threads didnt work, so i've put up the code without the threads
public class Main {
public static void main(String[] args){
Random r = new Random(System.currentTimeMillis());
int n = r.nextInt(101) + 50;
int[] a = new int[n];
for(int i = 0; i < n; i++)
a[i] = r.nextInt(100);
n = r.nextInt(101) + 50;
int[] b = new int[n];
for(int i = 0; i < n; i++)
b[i] = r.nextInt(100);
SortThread t1 = new SortThread(a);
SortThread t2 = new SortThread(b);
MergeThread m = new MergeThread(t1.get(),t2.get());
System.out.println(Arrays.toString(m.get()));
}
}
public class SortThread {
int[] x;
public SortThread(int[] x){
this.x = x;
run();
}
public void run(){
sort(x);
}
private void sort(int[] x){
for(int i = 0; i < x.length ; i++){
int indexOfSmallest = findIndexOfSmallest(x, i);
int t = x[i];
x[i] = x[indexOfSmallest];
x[indexOfSmallest] = t;
}
}
private int findIndexOfSmallest(int[] a, int from){
int indexOfSmallest = from;
for(int i = from; i < a.length; i++)
if(a[i] < a[indexOfSmallest])
indexOfSmallest = i;
return indexOfSmallest;
}
public int[] get(){
return x;
}
}
public class MergeThread {
int[] a;
int[] b;
int[] c;
public MergeThread(int[] a, int[] b){
this.a = a;
this.b = b;
c = new int[a.length + b.length];
run();
}
public void run(){
merge();
}
private void merge(){
int aIndex = 0, bIndex = 0, cIndex = 0;
while(aIndex < a.length && bIndex < b.length)
if(a[aIndex] < b[bIndex])
c[cIndex++] = a[aIndex++];
else
c[cIndex++] = b[bIndex++];
while(aIndex < a.length)
c[cIndex++] = a[aIndex++];
while(bIndex < b.length)
c[cIndex++] = b[bIndex++];
}
public int[] get(){
return c;
}
}
A thread should implement the interface runnable and should override the method run.
Please Read Complete reference JAVA, it has many good examples.
Like i mentioned even if you extend thread/implement runnable, the thread you are creating has to be started by a start method, which should be overrided again.
public void start () { System.out.println("Starting " + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } }
After this new can create a new instance of your thread and start it . In your case It should be
t1.start()
t2.start()
m.start()

The thread MultiplicationThreading cannot be resolved to a type

My goal here is to use multithreading programming to make a matrix multiplication application of two matrices. I am having an error in the Matrix.java class where I create a new thread called MultiplicationThreading. The console says it cannot resolve it to a type. This is the only error in my code and I am trying to figure out if there is a better way to write this line.
Here is my Matrix.java, where the problem is located at the new thread MultiplicationThreading.
package src;
public class Matrix {
public static int NUM_THREADS = 10;
public static void main(String args[])
{
int i; // row
int j; // column
int A[][] = { { 1, 4 }, { 2, 5 }, { 3, 6 } };
int B[][] = { { 8, 7, 6 }, { 5, 4, 3 } };
int C[][] = new int[3][3];
Thread[] matrixWorker = new Thread[NUM_THREADS];
/**
* Creates threads in order to multiply
*/
for (i = 0; i < 3; i++){ //rows
for (j = 0; j < 3; j++) { //columns
matrixWorker[i] = new Thread(new MultiplicationThreading(i, j, A, B,C)); //ERROR IS HERE
matrixWorker[i].start();
matrixWorker[i].join();
}
}
/**
* Prints out Matrix C
*/
System.out.println("Matrix: ");
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
System.out.print(C[i][j] + ", ");
}
System.out.print("\n");
}
}
}
If it helps, this is my other class, called MultipleThread.java
package src;
public class MultipleThread implements Runnable {
private int i; // row
private int j; // column
private int A[][];
private int B[][];
private int C[][];
public MultipleThread(int row, int col, int A[][], int B[][], int
C[][]) {
this.i = row;
this.j = col;
this.A = A;
this.B = B;
this.C = C;
}
/**
* Calculates matrix product in C[row][column]
*/
public void run() {
for (int t = 0; t < B.length; t++) {
C[i][j] += (A[i][t]) * (B[t][j]);
}
}
}
you have put the name of class incorrectly.
matrixWorker[i] = new Thread(new MultipleThread(i, j, A, B,C));
//ERROR IS HERE

Program with threads for matrix multiplication

I'm trying to create a Java program with threads for matrix multiplication. This is the source code:
import java.util.Random;
public class MatrixTest {
//Creating the matrix
static int[][] mat = new int[3][3];
static int[][] mat2 = new int[3][3];
static int[][] result = new int[3][3];
public static void main(String[] args) {
//Creating the object of random class
Random rand = new Random();
//Filling first matrix with random values
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[i].length; j++) {
mat[i][j] = rand.nextInt(10);
}
}
//Filling second matrix with random values
for (int i = 0; i < mat2.length; i++) {
for (int j = 0; j < mat2[i].length; j++) {
mat2[i][j] = rand.nextInt(10);
}
}
try {
//Object of multiply Class
Multiply multiply = new Multiply(3, 3);
//Threads
MatrixMultiplier thread1 = new MatrixMultiplier(multiply);
MatrixMultiplier thread2 = new MatrixMultiplier(multiply);
MatrixMultiplier thread3 = new MatrixMultiplier(multiply);
//Implementing threads
Thread th1 = new Thread(thread1);
Thread th2 = new Thread(thread2);
Thread th3 = new Thread(thread3);
//Starting threads
th1.start();
th2.start();
th3.start();
th1.join();
th2.join();
th3.join();
} catch (Exception e) {
e.printStackTrace();
}
//Printing the result
System.out.println("\n\nResult:");
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[i].length; j++) {
System.out.print(result[i][j] + " ");
}
System.out.println();
}
}//End main
}//End Class
//Multiply Class
class Multiply extends MatrixTest {
private int i;
private int j;
private int chance;
public Multiply(int i, int j) {
this.i = i;
this.j = j;
chance = 0;
}
//Matrix Multiplication Function
public synchronized void multiplyMatrix() {
int sum = 0;
int a = 0;
for (a = 0; a < i; a++) {
sum = 0;
for (int b = 0; b < j; b++) {
sum = sum + mat[chance][b] * mat2[b][a];
}
result[chance][a] = sum;
}
if (chance >= i)
return;
chance++;
}
}//End multiply class
//Thread Class
class MatrixMultiplier implements Runnable {
private final Multiply mul;
public MatrixMultiplier(Multiply mul) {
this.mul = mul;
}
#Override
public void run() {
mul.multiplyMatrix();
}
}
I just tried on Eclipse and it works, but now I want to create another version of that program in which, I use one thread for each cell that I'll have on the result matrix. For example I've got two 3x3 matrices. So the result matrix will be 3x3. Then, I want to use 9 threads to calculate each one of the 9 cells of the result matrix.
Can anyone help me?
You can create n Threads as follows (Note: numberOfThreads is the number of threads that you want to create. This will be the number of cells):
List<Thread> threads = new ArrayList<>(numberOfThreads);
for (int x = 0; x < numberOfThreads; x++) {
Thread t = new Thread(new MatrixMultiplier(multiply));
t.start();
threads.add(t);
}
for (Thread t : threads) {
t.join();
}
Please use the new Executor framework to create Threads, instead of manually doing the plumbing.
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreadsInPool);
for (int i = 0; i < numberOfThreads; i++) {
Runnable worker = new Thread(new MatrixMultiplier(multiply));;
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
With this code i think that i resolve my problem. I don't use synchronized in the methods but i think that is not necessary in that case.
import java.util.Scanner;
class MatrixProduct extends Thread {
private int[][] A;
private int[][] B;
private int[][] C;
private int rig, col;
private int dim;
public MatrixProduct(int[][] A, int[][] B, int[][] C, int rig, int col, int dim_com) {
this.A = A;
this.B = B;
this.C = C;
this.rig = rig;
this.col = col;
this.dim = dim_com;
}
public void run() {
for (int i = 0; i < dim; i++) {
C[rig][col] += A[rig][i] * B[i][col];
}
System.out.println("Thread " + rig + "," + col + " complete.");
}
}
public class MatrixMultiplication {
public static void main(String[] args) {
Scanner In = new Scanner(System.in);
System.out.print("Row of Matrix A: ");
int rA = In.nextInt();
System.out.print("Column of Matrix A: ");
int cA = In.nextInt();
System.out.print("Row of Matrix B: ");
int rB = In.nextInt();
System.out.print("Column of Matrix B: ");
int cB = In.nextInt();
System.out.println();
if (cA != rB) {
System.out.println("We can't do the matrix product!");
System.exit(-1);
}
System.out.println("The matrix result from product will be " + rA + " x " + cB);
System.out.println();
int[][] A = new int[rA][cA];
int[][] B = new int[rB][cB];
int[][] C = new int[rA][cB];
MatrixProduct[][] thrd = new MatrixProduct[rA][cB];
System.out.println("Insert A:");
System.out.println();
for (int i = 0; i < rA; i++) {
for (int j = 0; j < cA; j++) {
System.out.print(i + "," + j + " = ");
A[i][j] = In.nextInt();
}
}
System.out.println();
System.out.println("Insert B:");
System.out.println();
for (int i = 0; i < rB; i++) {
for (int j = 0; j < cB; j++) {
System.out.print(i + "," + j + " = ");
B[i][j] = In.nextInt();
}
}
System.out.println();
for (int i = 0; i < rA; i++) {
for (int j = 0; j < cB; j++) {
thrd[i][j] = new MatrixProduct(A, B, C, i, j, cA);
thrd[i][j].start();
}
}
for (int i = 0; i < rA; i++) {
for (int j = 0; j < cB; j++) {
try {
thrd[i][j].join();
} catch (InterruptedException e) {
}
}
}
System.out.println();
System.out.println("Result");
System.out.println();
for (int i = 0; i < rA; i++) {
for (int j = 0; j < cB; j++) {
System.out.print(C[i][j] + " ");
}
System.out.println();
}
}
}
Consider Matrix.java and Main.java as follows.
public class Matrix extends Thread {
private static int[][] a;
private static int[][] b;
private static int[][] c;
/* You might need other variables as well */
private int i;
private int j;
private int z1;
private int s;
private int k;
public Matrix(int[][] A, final int[][] B, final int[][] C, int i, int j, int z1) { // need to change this, might
// need some information
a = A;
b = B;
c = C;
this.i = i;
this.j = j;
this.z1 = z1; // a[0].length
}
public void run() {
synchronized (c) {
// 3. How to allocate work for each thread (recall it is the run function which
// all the threads execute)
// Here this code implements the allocated work for perticular thread
// Each element of the resulting matrix will generate by a perticular thread
for (s = 0, k = 0; k < z1; k++)
s += a[i][k] * b[k][j];
c[i][j] = s;
}
}
public static int[][] returnC() {
return c;
}
public static int[][] multiply(final int[][] a, final int[][] b) {
/*
* check if multipication can be done, if not return null allocate required
* memory return a * b
*/
final int x = a.length;
final int y = b[0].length;
final int z1 = a[0].length;
final int z2 = b.length;
if (z1 != z2) {
System.out.println("Cannnot multiply");
return null;
}
final int[][] c = new int[x][y];
int i, j;
// 1. How to use threads to parallelize the operation?
// Every element in the resulting matrix will be determined by a different
// thread
// 2. How may threads to use?
// x * y threads are used to generate the result.
for (i = 0; i < x; i++)
for (j = 0; j < y; j++) {
try {
Matrix temp_thread = new Matrix(a, b, c, i, j, z1);
temp_thread.start();
// 4. How to synchronize?
// synchronized() is used with join() to guarantee that the perticular thread
// will be accessed first
temp_thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return Matrix.returnC();
}
}
You can use Main.java to give 2 matrices that need to be multiplied.
class Main {
public static int[][] a = {
{1, 1, 1},
{1, 1, 1},
{1, 1, 1}};
public static int[][] b = {
{1},
{1},
{1}};
public static void print_matrix(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++)
System.out.print(a[i][j] + " ");
System.out.println();
}
}
public static void main(String[] args) {
int[][] x = Matrix.multiply(a, b);
print_matrix(x); // see if the multipication is correct
}
}
In simple terms, what you all need to do is,
1) Create n (no of cells in resultant matrix) threads. Assign their roles. (Ex: Consider M X N, where M and N are matrices. 'thread1' is responsible for the multiplication of M's row_1 elements with N's column_1 elements and storing the result. This is the value for the resultant matrix's cell_1.)
2) Start each thread's process. (by start() method)
3) Wait until all the threads finish their processes and store the resultant value of each cell. Because those processes should be finished before displaying the resultant matrix. (You can do this by join() methods, and other possibilities too)
4) Now, you can display the resultant matrix.
Note:
1) Since, in this example, the shared resources (M and N) are only used to read only purpose, you don't need to use 'synchronized' methods to access them.
2) You can see, in this program, there are a group of threads running and all of them needs to achieve a specific status by their own, before continuing the next step of the whole program. This multi-threaded programming model is known as a Barrier.
Tried below code in eclipse as per thread for each cell. It works fine, you can check it.
class ResMatrix {
static int[][] arrres = new int[2][2];
}
class Matrix {
int[][] arr = new int[2][2];
void setV(int v) {
//int tmp = v;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
arr[i][j] = v;
v = v + 1;
}
}
}
int[][] getV() {
return arr;
}
}
class Mul extends Thread {
public int row;
public int col;
Matrix m;
Matrix m1;
Mul(int row, int col, Matrix m, Matrix m1) {
this.row = row;
this.col = col;
this.m = m;
this.m1 = m1;
}
public void run() {
//System.out.println("Started Thread: " + Thread.currentThread().getName());
int tmp = 0;
for (int i = 0; i < 2; i++) {
tmp = tmp + this.m.getV()[row][i] * this.m1.getV()[i][col];
}
ResMatrix.arrres[row][col] = tmp;
System.out.println("Started Thread END: " + Thread.currentThread().getName());
}
}
public class Test {
//static int[][] arrres =new int[2][2];
public static void main(String[] args) throws InterruptedException {
Matrix mm = new Matrix();
mm.setV(1);
Matrix mm1 = new Matrix();
mm1.setV(2);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
Mul mul = new Mul(i, j, mm, mm1);
mul.start();
// mul.join();
}
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
System.out.println("VALUE: " + ResMatrix.arrres[i][j]);
}
}
}
}
In my solution I assigned to each worker a number of rows numRowForThread equals to: (number of rows of matA) / (number of threads).
public class MatMulConcur {
private final static int NUM_OF_THREAD = 1;
private static Mat matC;
public static Mat matmul(Mat matA, Mat matB) {
matC = new Mat(matA.getNRows(), matB.getNColumns());
return mul(matA, matB);
}
private static Mat mul(Mat matA, Mat matB) {
int numRowForThread;
int numRowA = matA.getNRows();
int startRow = 0;
Worker[] myWorker = new Worker[NUM_OF_THREAD];
for (int j = 0; j < NUM_OF_THREAD; j++) {
if (j < NUM_OF_THREAD - 1) {
numRowForThread = (numRowA / NUM_OF_THREAD);
} else {
numRowForThread = (numRowA / NUM_OF_THREAD) + (numRowA % NUM_OF_THREAD);
}
myWorker[j] = new Worker(startRow, startRow + numRowForThread, matA, matB);
myWorker[j].start();
startRow += numRowForThread;
}
for (Worker worker : myWorker) {
try {
worker.join();
} catch (InterruptedException e) {
}
}
return matC;
}
private static class Worker extends Thread {
private int startRow, stopRow;
private Mat matA, matB;
public Worker(int startRow, int stopRow, Mat matA, Mat matB) {
super();
this.startRow = startRow;
this.stopRow = stopRow;
this.matA = matA;
this.matB = matB;
}
#Override
public void run() {
for (int i = startRow; i < stopRow; i++) {
for (int j = 0; j < matB.getNColumns(); j++) {
double sum = 0;
for (int k = 0; k < matA.getNColumns(); k++) {
sum += matA.get(i, k) * matB.get(k, j);
}
matC.set(i, j, sum);
}
}
}
}
}
where for the class Mat, I used this implementation:
public class Mat {
private double[][] mat;
public Mat(int n, int m) {
mat = new double[n][m];
}
public void set(int i, int j, double v) {
mat[i][j] = v;
}
public double get(int i, int j) {
return mat[i][j];
}
public int getNRows() {
return mat.length;
}
public int getNColumns() {
return mat[0].length;
}
}

How to simulate in Java a stale value read by a thread?

I would like to simulate a situation which is mentioned in books about concurrency - that without a proper synchronization one thread can see a stale value of a variable that has been already modified by a different thread. This could happen because for example a CPU cache.
To do this I have written the following program. The idea is that there are 4 threads that initialize a different part of a shared array. The 5th thread (main, parent thread) waits until all 4 previous threads are done, iterates over the shared array and adds its values (always 1 or if I'm lucky null, which would mean a stale value)
package p1;
class ArrFill implements Runnable {
int l, r;
Integer[] arr;
ArrFill(int l, int r, Integer[] arr) {
this.l = l;
this.r = r;
this.arr = arr;
}
#Override
public void run() {
for(int i = l; i < r; i++)
arr[i] = new Integer(1);
}
}
public class Main {
final static int MAX = 10000000;
final static int tnum = 4;
public static void main(String[] args) throws InterruptedException {
int cores = Runtime.getRuntime().availableProcessors();
System.out.println(cores);
Integer[] arr = new Integer[MAX];
Thread[] t = new Thread[tnum];
if(MAX % tnum != 0)
throw new IllegalStateException();
int step = MAX / tnum;
int l = 0, r = 0;
for(int i = 0; i < tnum; i++) {
l = r;
r += step;
t[i] = new Thread(new ArrFill(l, r, arr));
t[i].start();
}
for(int i = 0; i < tnum; i++)
t[i].join();
int res = 0;
for(int i = 0; i < MAX; i++)
if(arr[i] != null)
res += arr[i];
System.out.println(res == MAX);
}
}
I have run this program many times although I never seen a stale value (null). I have 2 cores. Do you have any idea how this program could be improved to actually present the cached value phenomena? Or maybe you have a completly different approach?
Thanks!

Categories

Resources