Introducing

Getting Start

std::in

This article is about a few simple java thread examples for beginners, each example has an use case(business) and the solution. It's better to have review about java threading basis before you attempt to read this article.This post contains some case study about multi-threaded applications. These examples are really easy, they may need too much code, but the definition is easy and there is no room for being worry. #0 Type It Simply, user has got 5 attempt chances to type down a sentence by, simultaneously a thread is run to count the elapsing time.

package wasys911992.blogger.example.thread; import java.io.BufferedReader; import java.io.InputStreamReader; /** * by github.com/911992 * arashmd.blogspot.com */ public class Timer implements Runnable { public void run() { int c = 0B0;// int var= 0B<<binary value here>>, 0X<<hex value here>>, 0<<octed value>> try { while (!Thread.currentThread().isInterrupted()) { c++; Thread.sleep(1000); } } catch (InterruptedException ex) { } finally { System.out.println("Time elapsed: " + c + " seconds"); } } public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); Thread timer_thread = new Thread(new Timer()); int att = 1; System.out.println("Type \"Victory is ours\""); timer_thread.start(); while (!(br.readLine()).trim().equalsIgnoreCase("Victory is ours") && att < 5) { System.out.println("NOPE! wrong input, type \"Victory is ours\""); att++; } timer_thread.interrupt(); if (att < 5) { System.out.println("Perfect you could type a simple sentence after "+(att)+" attempts"); } else { System.out.println("Ehh... you attemped 5 times to type down a simple sentence and couldn't!"); } } }

Explanation

package wasys911992.blogger.example.thread; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class Base { /** * by github.com/911992 * arashmd.blogspot.com */ public static void main(String[] args){ for(int i=0;i<10;i++){ new Thread(new BadThread("./output/"+i+".text")).start();//any path you like, would be /home/user or C:/ } } } class BadThread implements Runnable{ public BadThread(String filePath) throws IOException{ File f=new File(filePath); if(f.exists()==false){f.createNewFile();} dos=new DataOutputStream(new FileOutputStream(filePath)); } private DataOutputStream dos; double val=0.0D; @Override public void run() { try{ for(int i=0;i<1024000;i++){//it could be even more val=Math.random(); for(int j=0;j<8;j++){ dos.writeDouble(val+j);//there is no buffering [0] } } dos.flush(); dos.close(); }catch(Exception e){return;} } }

Explanations

BadThread

f(x)={x*x}

f(x)={|X|*2}.

package wasys911992.blogger.example.thread; import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; //this is our formula signature interface Function{ Double calculate(double arg); } class PowerFunction implements Function{//a sample of formula @Override public Double calculate(double arg) { return Math.pow(arg, 2); } } class X2Finction implements Function{//another sample of formula @Override public Double calculate(double arg) { return Math.abs(arg)*2; } } public class GraphPointer{ static int resCount=0;//indicates the number of finished job(thread) //number of values need to process, here we are talking about sequential numbers, but could be in any order static final int totalValue=360; static DataOutputStream out;//for saving the response to file, stream static Double[] res;//array to keep result /** * by github.com/911992 * arashmd.blogspot.com */ public static void main(String[] args) throws Exception{ GraphPointer.out=new DataOutputStream(new FileOutputStream("C:/output/dataRes.txt")); //create a function of a formula, power, 2x, etc... Function f=new PowerFunction(); //init the result array res=new Double[GraphPointer.totalValue]; //for each element in array //we sued the -180 -> 179 numbers, this not a rule, could be in any order for(int i=0,val=-(res.length/2);i< res.length ;i ++,val ++){ //run thread for each new Thread( new FunctionInvoker(val, f, i) ).start(); } } public synchronized static void addResultSet(){ GraphPointer.resCount++; //if all of the results have calculated if(GraphPointer.resCount==GraphPointer.totalValue){ //persist the data GraphPointer.persistData(); } } //this method gets called when all of results get calculated private static void persistData(){ try{ //here it writes doubles as string, could be double or in any format for(Double d : res){out.writeChars("["+d.toString()+"] ");} out.flush();out.close();}catch(Exception ex ){ex.printStackTrace();} System.out.println("DONE!"); } public static void setData(int i,Double val){ res[i]=val;//set the calculated value into the desire index } } //this guys runs the functions as thread class FunctionInvoker implements Runnable{ Function f;//reference of function(formula) double arg;int i; public FunctionInvoker(double arg,Function f,int i){this.arg=arg;this.f=f;this.i=i;} @Override public void run() { //get the result from the function and pass it to get persist in array GraphPointer.setData(i,f.calculate(arg)); //tell system that a result has been done. GraphPointer.addResultSet(); } }

Explanations

static setData(i:int,val:Double):void

synchronized static addResultSet():void

setDate()

resCount

The main thread starts the timer thread and gets inputs from user. Either if user inputs the correct or wrong answer within 5 attempts(chance), main method will interrupt the timer thread indicates the stop signal for. #1 Big File Maker This example is about an application tries to make big files in a folder, but concurrently, it makes 10 large file at a same time, this kind of application is not really useful anymore, it more looks like a disturbing application, but it would be fun, for example, filling up whole of your memory flash disk (Don't do that).We have one implementation of the task because all of the them follow a rule. As system needs to run a task many times, then we run 10 instance of implementation concurrently by threads.The main class(thread) creates n number(10 here) instances of, which each instance accepts a string indicates the target file path to be created.You may change the number of threads, the path, or the size need to be created. #2 Array Initializing Considering a simple game having too many objects. It results too much processes for calculating object's location and rendering.A simple or complex math formula would be used for calculating and rendering an object in the game, free fall for example, or throwing an object. We use two formulas here for instance, one isand another one isConsider the above diagram, it's talking about a 10-length array that each index value should multiply by itself(power) and gets stored into naother array, so here for 10 values, we run 10 threads. Each thread calculates a value.As you see in above code, the main thread just runs 360 threads concurrently. Results(y points) are stored in an array(res) that each thread saves its result to the related index.There is an issue, after running threads the array data should persist in a file, but the problem is here, how to realize all threads returned the result? we didn't use of either semaphore or pool here, but we count the results, it's not really good idea, but it's a way to identifying how many threads has finished.this method is called when a thread calculates a result then the thread passes the index number and the result to it for storing the data. you may ask now why isn't it synchronized? why doesn't it lock the array to saving data? because we sure this is impossible that two threads calculate one index, definitely each index of the array is belong to one thread, also there is no any reading unless all of the array indexes initialized.This is called bymethod to count the results in order to persist the array once all the results are ready(calculated). It locks the(indicates the calculated results) for updating because this is a read-modify update. #3 Array Lookup Considering a big data array or context such as a big database index page, and finding some data is required. For example counting the prime numbers ranged 0 to 16777216, or finding strings which containWe would see the whole array as multiple small arrays, for example considering a 16777216-len array as 32 x 524288-len arrays. Then simply each array will be looked up by a thread, something like the following diagram.

package wasys911992.blogger.example.thread; //import java.util.ArrayList; /** * by github.com/911992 * arashmd.blogspot.com */ public class IndexSearch { static final int data[]=new int[16777216];//our data static{//Initializing the data linear(single-thread) long st=System.currentTimeMillis(); for(int i=0;i<data.length;i++){ data[i]=i; } st=System.currentTimeMillis()-st; System.out.printf("Initilization done | elapsed time: %d ms

",st); } static final Object lock_obj=new Object(); //there are 1077871 prime numbers between 0 to 16777216 //static ArrayList<Integer> indexes=new ArrayList<Integer>(1077871);//for persisting the prime numbers static volatile int total_primes=0; public static void main(String[] args) throws Exception { long st=System.currentTimeMillis();//get start processing time for(int i=0;i<data.length;i++){//run the process linear if(is_prime(data[i])){total_primes++;/*indexes.add(i);*/}//check the data } st=System.currentTimeMillis()-st;//get and calculate the elapsed time System.out.printf("Single thread | elapsed time: %d ms

",st); // indexes.clear(); total_primes=0; Thread[] guys=new Thread[32]; int each_len=data.length/guys.length; st=System.currentTimeMillis(); for(int i=0;i<guys.length;i++){ guys[i]=new Thread(new SearchWorker(i*each_len, each_len)); guys[i].start();//run each part } for(int i=0;i<guys.length;i++){ guys[i].join(); } st=System.currentTimeMillis()-st; System.out.printf("Parallel(multithread) | elapsed time: %d ms

",st); } static boolean is_prime(int a) { if (a%2==0) return false; for(int i=3;i*i<=a;i+=2) { if(a%i==0){ return false;} } return true; } } class SearchWorker implements Runnable{ int offset,len; public SearchWorker(int offset, int len) { // System.out.println(offset + " "+ (offset+len)); this.offset = offset; this.len = len; } public void run() { for(int i=offset;i<(offset+len);i++){ if(IndexSearch.is_prime(IndexSearch.data[i])){ synchronized (IndexSearch.lock_obj) { IndexSearch.total_primes+=1; //IndexSearch.indexes.add(i); } } } } }

Explanation

package wasys911992.blogger.example.thread; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; public class Encrypt { /** * @param args * @throws IOException * @throws InterruptedException */ public static void main(String[] args) throws IOException, InterruptedException { FileInputStream fis=new FileInputStream("c:/input.txt");//input file either encrypted or raw file Encrypt e=new Encrypt(); //set the encryptMode to false for decryption, true for encryption //e.encryptMode=false;//note that set it false when you are decrypting an encrypted file(no normal file) [0] byte[] data=new byte[16];int res;//here it reads 128 bits in each block int sequence=1; long st=System.currentTimeMillis(); while(true){ try { res=fis.read(data); //read 16 bytes from the raw/encrypted file(stream) if(res==-1){break;}//if End of stream (EOS) reached if(res==16){//if this is a complete block e.run(data, sequence);//pass the data and the sequence number to the thread pool }else{//if it's a incomplete block, so array copy is not needed for the last one. e.run(data, sequence); } sequence++;//next sequence means, next block } catch (Exception ex) { ex.printStackTrace();return; } } e.join();//waits until every running threads finishes its job(encrypt) [1] e.shutdown();//shutdown the threads(pools) System.out.print("File encryption/decryption finished! time: "+(System.currentTimeMillis()-st)+" ms"); } public boolean encryptMode=true;//by default, system encrypt the file private List<EncryptModule> readyThreads, busyThreads;//list of ready and running threads [2] int maxThreadSize=64;//maximum size of running thread at a time, would be more or less Writer w; private Encrypt() throws IOException{ try { w=new Writer("C:/output/res.txt");//set the output file } catch (FileNotFoundException e) {} readyThreads=new ArrayList<EncryptModule>(maxThreadSize); busyThreads=new ArrayList<EncryptModule>(maxThreadSize); for(int i=0;i<maxThreadSize;i++){ EncryptModule em=new EncryptModule(w,this); new Thread(em).start();//starts each thread [3] readyThreads.add(em);//filling the readyThreads(pool) [4] } } private synchronized void run(byte[] data,int sequence) throws InterruptedException{ //[5] if(readyThreads.size()==0){this.wait();}//if there is no thread ready, so wait for one! [6] EncryptModule em=readyThreads.get(0);//get a ready thread readyThreads.remove(0);//remove it from the ready ones busyThreads.add(em);//add it to busy pool em.newTask(data, sequence);//pass the block to process [7] } public synchronized void backToMgr(EncryptModule em){//called by EncryptModule when its job get finished [12] busyThreads.remove(em);//remove the thread from busy ones readyThreads.add(em);// and set it as ready if(readyThreads.size()==maxThreadSize){//if all of the threads has back, time to shutting down the system synchronized (readyThreads) { readyThreads.notify();//notify the join [8] thread } } try{ this.notify();//notify that a new ready thread has added to the pool [5] }catch(Exception e){} } void join(){ synchronized (readyThreads) { if(readyThreads.size()<maxThreadSize){//if threads are still in action try{ readyThreads.wait();//Waits until backToMgr notify that all threads have back //[16] }catch(Exception e){e.printStackTrace();} } } } void shutdown() throws IOException{ w.close();//close the file handler for(EncryptModule e : readyThreads){ e.shutdown();//kills every thread in the pool [9] } } } /* *1 2 3 4 F 9 C 8 *5 6 7 8 ----\\ A 1 B E *9 A B C ----// 5 4 G 2 *D E F G 7 D 3 6 * *Encrypt algorithm * outData[0]= inData[14]; outData[1]= inData[8]; outData[2]= inData[11]; outData[3]= inData[7]; outData[4]= inData[9]; outData[5]= inData[0]; outData[6]= inData[10]; outData[7]= inData[13]; outData[8]= inData[4]; outData[9]= inData[3]; outData[10]=inData[15]; outData[11]=inData[1]; outData[12]=inData[6]; outData[13]=inData[12]; outData[14]=inData[2]; outData[15]=inData[5]; ==================================================================================================================== *F 9 C 8 1 2 3 4 *A 1 B E ----\\ 5 6 7 8 *5 4 G 2 ----// 9 A B C *7 D 3 6 D E F G *Decrypt algorithm * outData[0]= inData[5]; outData[1]= inData[11]; outData[2]= inData[14]; outData[3]= inData[9]; outData[4]= inData[8]; outData[5]= inData[15]; outData[6]= inData[12]; outData[7]= inData[3]; outData[8]= inData[1]; outData[9]= inData[4]; outData[10]=inData[6]; outData[11]=inData[2]; outData[12]=inData[13]; outData[13]=inData[7]; outData[14]=inData[0]; outData[15]=inData[10]; */ class EncryptModule implements Runnable{//encryption module, each instance has a 128 bits data [10] private Writer w;int sequence;Encrypt mgr; public EncryptModule(Writer w,Encrypt e){this.w=w;this.mgr=e;} byte[] inData,outData;Thread thisThread; private volatile boolean shutdown=false; private Object lock=new Object(); @Override public void run() {//starting thread at the creation time [3] thisThread=Thread.currentThread();//obtaining the current(this) thread synchronized (lock) { while(this.shutdown==false){ try{ lock.wait();//waits for a new task... [13] if(inData.length==16){//if it's about processing a complete(128 bits) block outData=new byte[16]; if(mgr.encryptMode){//if we need to encrypt outData[0]= inData[14]; outData[1]= inData[8]; outData[2]= inData[11]; outData[3]= inData[7]; outData[4]= inData[9]; outData[5]= inData[0]; outData[6]= inData[10]; outData[7]= inData[13]; outData[8]= inData[4]; outData[9]= inData[3]; outData[10]=inData[15]; outData[11]=inData[1]; outData[12]=inData[6]; outData[13]=inData[12]; outData[14]=inData[2]; outData[15]=inData[5]; }else{//if we need to decrypt outData[0]= inData[5]; outData[1]= inData[11]; outData[2]= inData[14]; outData[3]= inData[9]; outData[4]= inData[8]; outData[5]= inData[15]; outData[6]= inData[12]; outData[7]= inData[3]; outData[8]= inData[1]; outData[9]= inData[4]; outData[10]=inData[6]; outData[11]=inData[2]; outData[12]=inData[13]; outData[13]=inData[7]; outData[14]=inData[0]; outData[15]=inData[10]; } }else{//if it's about a incomplete block outData=new byte[inData.length]; for(byte i=0, p=(byte)(inData.length-1);p>=0;p--,i++){//reverse the array outData[i]=inData[p]; } } try { w.write(sequence, outData);//write the encrypted/decrypted data [11] } catch (IOException e) { e.printStackTrace(); } mgr.backToMgr(this);//back to the ready pool [12] }catch(InterruptedException e){break;} } } } public void shutdown(){ shutdown=true; thisThread.interrupt(); } public void newTask(byte[] data,int sequence){//new task received [7] this.sequence=sequence;//set the new sequence number inData=new byte[data.length];//set the new block data System.arraycopy(data, 0, inData, 0, data.length);//copy the array to the local array synchronized (lock) { lock.notify();//signal this thread, that a new task have received [13] } } } class Writer{ private RandomAccessFile raf; public Writer(String filePath) throws IOException{ File f=new File(filePath); if(f.exists()==false){f.createNewFile();} raf=new RandomAccessFile(filePath, "rw"); } public synchronized void write(int arrayNumber,byte[] data) throws IOException{ raf.seek((arrayNumber-1)*16);//writes the data to the correct location of the file, 2nd. block, for 2nd. block raf.write(data); } public synchronized void close() throws IOException{ raf.close(); } }

Explanations

Encrypt

EncryptModule

encrypteMode

Encrypt (class)

synchronized run(data:byte[],sequence:int):void

synchronized backToMgr(em:EncryptModule):void

em

join()

join():void

readPool

backToMgr()

readPool

readyPool

shutdown():void

EncryptModule

EncryptModule class

Writer

Encrypt

lock

Encrypt

lock

Writer class

RandomAccessMemory



or like this

or like this

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

package wasys911992.blogger.example.thread; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import javax.imageio.ImageIO; public class Square { /** * by github.com/911992 * arashmd.blogspot.com */ static public MySemaphore ms; public static ImageWriter iw; final static int maxThread=8;//maximum of thread at a time final static int blockSize=128;//big square block size in pixel final static int width=768,height=512;//these size should be dividable by blockSize final static String filePath="C:/output/rand2.png";//set the target image location public static void main(String[] args) throws InterruptedException, IOException { ms=new MySemaphore(maxThread); //initializing semaphore iw=new ImageWriter(width, height, blockSize); //initializing Image Writer for(int i=0;i<( (width/blockSize) * (height/blockSize) );i++){// for each big block [0] ms.acquire(); //get permission from semaphore [1] new Thread(new SquareMaker(i, blockSize)).start();//starts the new thread [2] } ms.join(); //waits until all threads finish their job iw.WriteToFile(filePath);// flush and save the image System.out.println("Done!"); } } class SquareMaker implements Runnable{ static int smallBlocks=8;//number of small block in each big square 8->(8*8)=64 small squares overall, should dividable by big square width int blockSize,blockNo; public SquareMaker(int blockNo,int blockSize){ this.blockNo=blockNo;this.blockSize=blockSize;//setting block size(big square size) and the sequence number } @Override public void run() { int[] data=new int[blockSize*blockSize];//initializing the data array, it stores whole this big square colors int smallBlockSize=blockSize/SquareMaker.smallBlocks;//calculating how many pixels does a small square have? int index=0;int colorDiff=25;//maximum color difference value, would be more or less int baseColor=(int)(Math.random()*Integer.MIN_VALUE);//generate a random integer (color) value for(int i=0;i<(smallBlocks*smallBlocks);i++){//for each small square [3] //converting the randomized color into a 4 length array (alpha, red, green ,blue) byte[] color=ByteBuffer.allocate(4).putInt(baseColor).array(); int diff=(int)(Math.random()*colorDiff)+1;//generates a randomized color differences int ndiff=(diff%2==0)?diff:diff*-1;//multiply with -1, needs for darker colors //checks the commented if-else block below, this is the short form of that. color[1]=((color[1]&0XFF)+colorDiff<255 && (color[1]&0XFF)-colorDiff>0)? (byte)((color[1]&0xFF)+ndiff):(((color[1]&0xFF)+colorDiff>255)? (byte)((color[1]&0xFF)-diff):(byte)((color[1]&0xFF)+diff));//[4] color[2]=((color[2]&0XFF)+colorDiff<255 && (color[2]&0XFF)-colorDiff>0)? (byte)((color[2]&0xFF)+ndiff):(((color[2]&0xFF)+colorDiff>255)? (byte)((color[2]&0xFF)-diff):(byte)((color[2]&0xFF)+diff)); color[3]=((color[3]&0XFF)+colorDiff<255 && (color[3]&0XFF)-colorDiff>0)? (byte)((color[3]&0xFF)+ndiff):(((color[3]&0xFF)+colorDiff>255)? (byte)((color[3]&0xFF)-diff):(byte)((color[3]&0xFF)+diff)); /* if(((color[1]&0xFF)+colorDiff)>255){color[1]=(byte) ((color[1]&0xFF)-diff);} else if(((color[1]&0xFF)-colorDiff)<0){color[1]=(byte) ((color[1]&0xFF)+diff);} else{color[1]=(byte) ((color[1]&0xFF)+ndiff);} if(((color[2]&0xFF)+colorDiff)>255){color[2]=(byte) ((color[2]&0xFF)-diff);} else if(((color[2]&0xFF)-colorDiff)<0){color[2]=(byte) ((color[2]&0xFF)+diff);} else{color[2]=(byte) ((color[2]&0xFF)+ndiff);} if(((color[3]&0xFF)+colorDiff)>255){color[3]=(byte) ((color[3]&0xFF)-diff);} else if(((color[3]&0xFF)-colorDiff)<0){color[3]=(byte) ((color[3]&0xFF)+diff);} else{color[3]=(byte) ((color[3]&0xFF)+ndiff);} */ for(int k=0;k<(smallBlockSize*smallBlockSize);k++){//for each pixel in the small squares [5] //finding the this small square pixels location in data array index+=(smallBlockSize*smallBlockSize)*Math.floor(i/smallBlocks)*smallBlocks; index+=Math.floor(k/smallBlockSize)*smallBlockSize*smallBlocks; index+=(k%smallBlockSize)+((i%smallBlocks)*smallBlockSize); data[index]=ByteBuffer.wrap(color).getInt();//wrap the color array to the integer(color) value index=0; } } Square.iw.writeSection(blockNo, data);//big square is done, pass the data array to write to the target image Square.ms.release();//tells semaphore this thread has completed } } class ImageWriter { BufferedImage out; int width,height,blockSize,blockWidth; public ImageWriter(int width, int height, int blockSize){ this.width=width;this.height=height;this.blockSize=blockSize;this.blockWidth=this.width/this.blockSize; out=new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); } int blockX,blockY; public synchronized void writeSection(int blockNo,int[] data){ blockX=(blockNo%blockWidth)*blockSize;//find the location that this data(square) should get drawn blockY=(int)Math.floor(blockNo/blockWidth)*blockSize; System.out.println("Blockx: "+blockX+" blockY: "+blockY+" blockNo: "+blockNo+" array size: "+data.length); try{ out.setRGB(blockX,blockY, blockSize, blockSize, data, 0, blockSize);//set the data to the target image }catch(Exception e){e.printStackTrace();} } public synchronized void WriteToFile(String path) throws IOException{ out.flush(); ImageIO.write(out, "png", new File(path)); } } //find smeaphore tutorial here https://arashmd.blogspot.com/2013/06/java-threading.html class MySemaphore{ int maxThread,running; private Object joinWait=new Object(); public MySemaphore(int maxThreads){ this.maxThread=maxThreads; } public synchronized void acquire() throws InterruptedException{ if(running==maxThread){this.wait();} running++; } public synchronized void release(){ running--; if(running==0){synchronized(joinWait){try{joinWait.notify();}catch(Exception e){}}} try{ this.notify(); }catch(Exception e){} } public void join() throws InterruptedException{ synchronized (joinWait) { if(running==0){return;} joinWait.wait(); } } }

Explanations

Square

SquareMaker

The Disaster

Set the semaphore size to 1, it will be as same as single-thread application

Set the resolution to 4K (3840 x 2160), set the semaphore to a big value like 199000, and have a run

levelCount



Or like this

Or like this

package wasys911992.blogger.example.thread; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; class Parameter{//Parameter class for passing required data to threads and between classes public static final Color backColor=Color.black;//set the background color, white and black are cool enough :D public static int minDrawTime=33;//the minimum time square drawer should wait after each drawing process public Graphics2D g;//graphic that associated to each vertical portion, for drawing easier public int width,height;//indicated the width and height of eahc portion Parameter( Graphics2D g, int width, int height) { this.g = g; this.width = width; this.height = height; } } /** * by github.com/911992 * arashmd.blogspot.com */ public class Matrix implements Runnable {//Runnable implemented, this is the drawing thread public static void main(String[] args) throws Exception { new Matrix(); } JLabel lab; //Label for showing the target image //just some string at the top of the target image, would be your name :D String message="by github.com/911992(arashmd.blogspot.com) , wheel the mouse for changing the drawing speed, click to exit"; int levelCount=24;//number of vertical portion, change and see the effects (big ones doesn't make sense) int capSpace;//the space reminded (unusable) at the right and left sides BufferedImage img;//the target image that shows the target Graphics2D g;//the graphic associated the the img variable(target image) //number of times(frame) that drawing thread needs to refresh the target image in a second //the higher value will effects(improve) the animation smoothness and would cause the vertical-synchronization also needs more power //the lower value needs less power, decrease the animation smoothness and would cause the glitching int fps=60;//do not set less than 30 and and high values BufferedImage[] images;//arrays of portion images int screenWidth,screenHeight;//the width and height of the screen Matrix() throws Exception{ GraphicsDevice vc; JFrame f=new JFrame("Matrix by Arash"); GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment(); Toolkit tk=Toolkit.getDefaultToolkit(); //hide the cursor f.setCursor(f.getToolkit().createCustomCursor(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), new Point(0, 0), "null")); screenWidth=tk.getScreenSize().width;//get the screen size screenHeight= tk.getScreenSize().height; img=new BufferedImage(screenWidth,screenHeight, BufferedImage.TYPE_INT_ARGB);//init the target image as screen size lab=new JLabel(new ImageIcon(img), JLabel.CENTER);//init label and pass the target image to it as showing parameter f.getContentPane().add(lab); g=img.createGraphics(); vc=ge.getDefaultScreenDevice(); f.setUndecorated(true); f.setResizable(false); vc.setFullScreenWindow(f);//set the application as full screen lab.addMouseListener(new MouseListener() { @Override public void mouseReleased(MouseEvent arg0) {} @Override public void mousePressed(MouseEvent arg0) {} @Override public void mouseExited(MouseEvent arg0) {} @Override public void mouseEntered(MouseEvent arg0) {} @Override public void mouseClicked(MouseEvent arg0) {System.exit(0);}//exit the by a click }); //listening for mouse wheel for decreasing and increasing the fade-out/fade-in operation lab.addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent arg0) { if(arg0.getWheelRotation()==-1){ if(Parameter.minDrawTime>30){Parameter.minDrawTime-=10;}} else{if(Parameter.minDrawTime<60){Parameter.minDrawTime+=10;}}} }); images=new BufferedImage[levelCount];//init the portion images array //calculate the remind(unusable) space at right/left sides in target image capSpace=(int)(tk.getScreenSize().getWidth()%levelCount)/2; //calculate how many pixel is required for each portion image int width= (int) Math.floor(tk.getScreenSize().getWidth()/levelCount); for(int i=0;i<levelCount;i++){//in as for loop init portion image array images images[i]=new BufferedImage(width,tk.getScreenSize().height,BufferedImage.TYPE_4BYTE_ABGR); Parameter p=new Parameter(images[i].createGraphics(),width,tk.getScreenSize().height); new Thread(new VerticalPortion(p)).start();//starts a portion as a thread } Font font=new Font("courier new",Font.BOLD,16);//the font for showing the message at the top screen g.setFont(font); new Thread(this).start();//starts this thread(drawing thread) } @Override public void run() {//drawing thread start while(true){ g.setColor(Parameter.backColor);//set the color as it should be g.fillRect(0, 0, screenWidth, screenHeight);//purge the screen for(int i=0;i<images.length;i++){//draw each portion to the target img g.drawImage(images[i],(images[i].getWidth()*i)+((i==0)?capSpace:0),0,lab); } g.setColor(Color.gray);//set the color to draw the message, could be anything g.drawString(message,20, 20); lab.repaint();//force the label to refresh (refresh the image in fact) try { Thread.sleep(1000/fps);//wait for a while } catch (InterruptedException e) {} } }//drawing thread end } class VerticalPortion implements Runnable{ Parameter p; Thread[] trds; int verticalSpaceCap;//remind (unusable) space in top and bottom of the screen public VerticalPortion(Parameter p){ this.p=p; trds=new Thread[(int) Math.floor(p.height/p.width)];//calculate how many possible square would this portion have verticalSpaceCap=p.height%p.width;//calculate the unusable space p.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//enable antialias, it draws components smoother } @Override public void run() { for(int i=0;i<trds.length;i++){ Parameter px=new Parameter(p.g,p.width,p.height); trds[i]=new Thread(new SmallSquare(px,i*p.width+(verticalSpaceCap/2)));//one thread for one small square handler trds[i].start();//start the thread } } } class SmallSquare implements Runnable{ Parameter p; //two 4 length array that contains the RGBA of both background color and color square should be drawn by byte[] color,hcolor=new byte[4]; int topSpaceCap;//indicates how many pixel from top should this thread skip int margin; //spaces should be skip at each edge of square int j;//index for saving the last alpha value int waitTime;//time this thread should wait after each drawing int shapeSize;//the target shape size int increaseWidth;//the increment size for each square layer int colorDiff=10;//the value that effects each iteration color, could be more(more differences) or less public SmallSquare(Parameter p,int topSpaceCap) { this.p=p; this.topSpaceCap=topSpaceCap; margin=(int) (p.width*0.05); //split the randomized color into a 4 byte array as ARGB this.color=ByteBuffer.allocate(4).putInt((int)(Math.random()*Integer.MIN_VALUE)).array(); hcolor[0]=(byte)0; hcolor[1]=(byte)Parameter.backColor.getRed(); hcolor[2]=(byte)Parameter.backColor.getGreen(); hcolor[3]=(byte)Parameter.backColor.getBlue(); //Initialize the target full-transparent square size shapeSize=(p.width)-(margin*2); //initialize how many pixel should increase for the next layers increaseWidth=(int) ((shapeSize-(shapeSize*0.6))/10); } @Override public void run() { while(true){ waitTime=(int)(Math.random()*Parameter.minDrawTime*3);//get a random wait time in each iteration if(waitTime<Parameter.minDrawTime){waitTime=Parameter.minDrawTime;} int diff=(int)(Math.random()*colorDiff)+1; int ndiff=(diff%2==0)?diff:diff*-1; color[1]=((color[1]&0XFF)+colorDiff<255 && (color[1]&0XFF)-colorDiff>0)? (byte)((color[1]&0xFF)+ndiff):(((color[1]&0xFF)+colorDiff>255)? (byte)((color[1]&0xFF)-diff):(byte)((color[1]&0xFF)+diff)); color[2]=((color[2]&0XFF)+colorDiff<255 && (color[2]&0XFF)-colorDiff>0)? (byte)((color[2]&0xFF)+ndiff):(((color[2]&0xFF)+colorDiff>255)? (byte)((color[2]&0xFF)-diff):(byte)((color[2]&0xFF)+diff)); color[3]=((color[3]&0XFF)+colorDiff<255 && (color[3]&0XFF)-colorDiff>0)? (byte)((color[3]&0xFF)+ndiff):(((color[3]&0xFF)+colorDiff>255)? (byte)((color[3]&0xFF)-diff):(byte)((color[3]&0xFF)+diff)); //fade-in method 0, comment the method 1 if you wan to use this /*for(int i=0;i<10;i++){ if(i==9){color[0]=(byte) 255;} else{color[0]=(byte) (i*10);} synchronized (p.g){ if(i==9){p.g.setColor(new Color(color[1]&0xFF,color[2]&0xFF,color[3]&0xFF,color[0]&0xFF).brighter());} else{p.g.setColor(new Color(color[1]&0xFF,color[2]&0xFF,color[3]&0xFF,color[0]&0xFF));} p.g.fillRoundRect(margin+(i*increaseWidth),margin+(i*increaseWidth)+this.topSpaceCap, shapeSize-(i*increaseWidth*2),shapeSize-(i*increaseWidth*2),j,j); } try {Thread.sleep(waitTime);} catch (InterruptedException e) {} }*/ //fade-in method 0 //fade in method 1 for(int i=10;i>0;i--){ color[0]=(byte) (i*5);//sets the alpha for each layer of the square /*this synchronized block is required, because in a portion, there are(could be) more than 1 thread. *so because the portion image is shared belong to every thread, each thread need to lock the graphic object *and draw it's image, if there is no synchronized method, this is possible that thread 1 draw its line by *the color that thread 2 has been specified, just omit the synchronized block and see the difference! */ synchronized (p.g){//[0] //drawing brighter color for the center square if(i==10){p.g.setColor(new Color(color[1]&0xFF,color[2]&0xFF,color[3]&0xFF,255).brighter().brighter().brighter());} else{p.g.setColor(new Color(color[1]&0xFF,color[2]&0xFF,color[3]&0xFF,color[0]&0xFF));} p.g.fillRoundRect(margin+(i*increaseWidth),margin+(i*increaseWidth)+this.topSpaceCap, shapeSize-(i*increaseWidth*2),shapeSize-(i*increaseWidth*2),(10-i)*2,(10-i)*2); } try {Thread.sleep(waitTime);} catch (InterruptedException e) {} }//fade-in method 1 //fade-out for(int i=0;i<50;i++){ hcolor[0]=(byte) (i*5.1); synchronized (p.g){ p.g.setColor(new Color(hcolor[1]&0xFF,hcolor[2]&0xFF,hcolor[3]&0xFF, hcolor[0]&0xFF)); p.g.fillRect(margin,margin+this.topSpaceCap,shapeSize,shapeSize); } try {Thread.sleep(waitTime);} catch (InterruptedException e) {} }//fade-out } } }

Explination

@Override public void run() {//drawing thread start while(true){ g.setColor(Parameter.backColor);//set the color as it should be g.fillRect(0, 0, screenWidth, screenHeight);//purge the screen for(int i=0;i < images.length ; i++){//draw each portion to the target img g.drawImage(images[i],(images[i].getWidth()*i)+((i==0)?capSpace:0),0,lab); } g.setColor(Color.gray);//set the color to draw the message, could be anything g.drawString(message,20, 20); lab.repaint();//force the label to refresh (refresh the image in fact) try { Thread.sleep(1000/fps);//wait for a while } catch (InterruptedException e) {} } }//drawing thread end

@Override public void run() { while(true){ waitTime=(int)(Math.random()*Parameter.minDrawTime*3);//get a random wait time in each iteration if(waitTime<Parameter.minDrawTime){waitTime=Parameter.minDrawTime;} int diff=(int)(Math.random()*colorDiff)+1; int ndiff=(diff%2==0)?diff:diff*-1; color[1]=((color[1]&0XFF)+colorDiff<255 && (color[1]&0XFF)-colorDiff>0)? (byte)((color[1]&0xFF)+ndiff):(((color[1]&0xFF)+colorDiff>255)? (byte)((color[1]&0xFF)-diff):(byte)((color[1]&0xFF)+diff)); color[2]=((color[2]&0XFF)+colorDiff<255 && (color[2]&0XFF)-colorDiff>0)? (byte)((color[2]&0xFF)+ndiff):(((color[2]&0xFF)+colorDiff>255)? (byte)((color[2]&0xFF)-diff):(byte)((color[2]&0xFF)+diff)); color[3]=((color[3]&0XFF)+colorDiff<255 && (color[3]&0XFF)-colorDiff>0)? (byte)((color[3]&0xFF)+ndiff):(((color[3]&0xFF)+colorDiff>255)? (byte)((color[3]&0xFF)-diff):(byte)((color[3]&0xFF)+diff)); //fade in method 1 for(int i=10;i > 0;i--){ color[0]=(byte) (i*5);//sets the alpha for each layer of the square synchronized (p.g){//[0] //drawing brighter color for the center square if(i==10){p.g.setColor(new Color(color[1]&0xFF,color[2]&0xFF,color[3]&0xFF,255).brighter().brighter().brighter());} else{p.g.setColor(new Color(color[1]&0xFF,color[2]&0xFF,color[3]&0xFF,color[0]&0xFF));} p.g.fillRoundRect(margin+(i*increaseWidth),margin+(i*increaseWidth)+this.topSpaceCap, shapeSize-(i*increaseWidth*2),shapeSize-(i*increaseWidth*2),(10-i)*2,(10-i)*2); } try {Thread.sleep(waitTime);} catch (InterruptedException e) {} }//fade-in method 1 //fade-out for(int i=0;i < 50;i++){ hcolor[0]=(byte) (i*5.1); synchronized (p.g){ p.g.setColor(new Color(hcolor[1]&0xFF,hcolor[2]&0xFF,hcolor[3]&0xFF, hcolor[0]&0xFF)); p.g.fillRect(margin,margin+this.topSpaceCap,shapeSize,shapeSize); } try {Thread.sleep(waitTime);} catch (InterruptedException e) {} }//fade-out } }

A horse race game: this is very old and simple chance game, you know enough, but just a mention, it's about 5-7 horses that at the start the game each horse(thread) generates a random number (maybe between 14-16), and starts to reach the end line, while you bet on a horse that would win.

this is very old and simple chance game, you know enough, but just a mention, it's about 5-7 horses that at the start the game each horse(thread) generates a random number (maybe between 14-16), and starts to reach the end line, while you bet on a horse that would win. Counting numbers: a simple screen-like application (like lively squares), there some counting numbers in different sizes(one could get 20% of whole page, randomized) that each one are increasing, randomely each number has a increasing count.

a simple screen-like application (like lively squares), there some counting numbers in different sizes(one could get 20% of whole page, randomized) that each one are increasing, randomely each number has a increasing count. Cursor Enemies: (Zombies needs cursor) it's kind of fun gui application, okay there is full screen page with 5 slow-moving objects(a square, rectangle, something) that those guys find(move through) the cursor current position to reach the cursor, user has to run a way from objects. If any objects reaches the cursor position user will lost.