I'm creating a toy program in java using synchronized block. I have n "Pixelator" threads which pick a random pixel in a 1000x1000 image and assign it to the color of the Pixelator. Each pixel can only be assigned once. I write to a bufferedImage using a wrapper class that uses a synchronized method to write to the image. However, when I test with more than 1 thread, I do not see a speedup. Do you have a hint as to why that would be?
Relavant Code:
import java.awt.Color;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import java.util.ArrayList;
import java.util.Random;
public class q2 {
// The image constructed
public static BufferedImage img;
// Image dimensions; you could also retrieve these from the img object.
public static int width;
public static int height;
// simplified method for stack overflow example
public static int rgbFromN(int n) {
return -16755216;
}
public static void main(String[] args) {
Random r = new Random();
try {
// arg 0 is the width
width = 1000;
// arg 1 is the height
height = 1000;
// arg 2 is the number of threads
int nt = 1;
// create an image and initialize it to all 0's
img = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
synchronizedIMG simg = new synchronizedIMG(img);
for (int i=0;i<width;i++) {
for (int j=0;j<height;j++) {
img.setRGB(i,j,0);
}
}
Thread[] threads = new Thread[nt];
long startTime = System.currentTimeMillis();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Pixelator(rgbFromN(i),width,height,((width*height)/nt),simg));
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
long endTime = System.currentTimeMillis();
System.out.println("Time(ms): " + (endTime-startTime));
// Write out the image
File outputfile = new File("outputimage.png");
ImageIO.write(img, "png", outputfile);
} catch (Exception e) {
System.out.println("ERROR " +e);
e.printStackTrace();
}
}
}
class Pixelator implements Runnable {
int color;
int width;
int height;
int numPixels;
int currentPixels = 0;
synchronizedIMG simg;
public Pixelator(int color, int width, int height,int numPixels, synchronizedIMG simg){
this.color = color;
this.width = width;
this.height = height;
this.numPixels = numPixels;
this.simg = simg;
}
public void run() {
int randomX = 0;
int randomY = 0;
boolean success = false;
while(currentPixels < numPixels){
randomX = 0 + (int)(Math.random() * (width));
randomY = 0 + (int)(Math.random() * (height));
success = simg.setColor(color, randomX, randomY);
if(success){
currentPixels++;
}
}
return;
}
}
class synchronizedIMG{
BufferedImage img;
public synchronizedIMG(BufferedImage img){
this.img = img;
}
public synchronized boolean setColor(int color, int x, int y){
if(img.getRGB(x, y) == 0){
img.setRGB(x, y, color);
return true;
} else{
return false;
}
}
}
It requires a certain amount of time to the machine to manage the threads. In image processing, use two threads instead of one, does not reduce the processing time by 50%, but between 30 % to 40 according to the processing (empirical estimation with the multi-threaded classes of my own java library).
Moreover in your case, you don't do any major processing just simple computation. So it's longer to manage the threads than doing the processing on a single thread. Try to do a big convolution.
The biggest problem you face is that adding more threads will not increase the memory bandwidth of your system.
Your threads do nothing except compute random numbers and write them out to memory. Adding more threads potentially increases the speed with which you can compute the random numbers, but that probably was pretty fast to begin with. Math.random() is not a crypto-quality random number generator. It probably is very fast.
Unfortunately, your job isn't done until all of the bytes have been written out to memory. Your system has only one memory bus, and it can only go so fast. All of the threads have to contend for that resource.
Related
Currently I am programming an example for a java program which uses basic Multithreading. I want to show the advantage of the data composition principle in an image processing application that resembles a monochromatic filter. I load a picture in a buffer and then spawn four Threads which all compute different parts of the Image.
The image is divided into four slices and the computation time alone is lowered according to my expectations (3 to 4 times faster on a quadcore).
The problem is i try to avoid Race Conditions by giving each Thread a Buffer where the computed picture is saved. After the execution each Thread saves it's part of the picture in a jpg.
My question here is if there is a pattern i can use to save the different slices as one picture again while avoiding the dangers of the Shared mutable state variables.
If i use a static Variable in my Processing Class to reassemble the picture I get times that are even worse than the singlethreaded solutions.
How can i make the effiency that multithreading offers appearant in this example?
Thats my Code for the Multithreaded application:
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
public class Main {
static int threadCount=4;
public static void main(String[] args) {
// TODO Auto-generated method stub
BufferedImage original=null;
BufferedImage greyscale=null;
//loading Picture into Buffer
try{
original = ImageIO.read(new File("Desert.jpg"));
}
catch (IOException e)
{
e.printStackTrace();
}
ArrayList<Thread> threads = new ArrayList<Thread>();
//Creating Threads, each Thread gets a Copy of the Image
for( int i=0; i < threadCount; i++)
{
final int threadNumber =i;
threads.add(new Thread(new Processor2(deepCopy(original),threadNumber,threadCount)));}
//threads gets started
long start = System.currentTimeMillis();
for( int i=0; i < threadCount; i++){
threads.get(i).start();
}
for( int i=0; i < threadCount; i++){
try {
threads.get(i).join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
long end = System.currentTimeMillis();
long seconds = (end-start);
System.out.println("Dauer: "+seconds+" ms.");
}
//Method that copies the Image
static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
}
The Threads that get spawned Execute this code:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Processor2 implements Runnable {
BufferedImage greyscale;
BufferedImage original;
int threadNumber, threadCount;
//The Constructor gets the Image, the total number of Threads and the own Threadnumber.
Processor2(BufferedImage image, int x, int y){
this.original=image;
threadNumber=x;
threadCount=y;
}
Object lock =new Object();
#Override
// The run Method goes through the pixel of the assignes slide of the picture, renders it monochromatic and then saves it in an ImageBuffer. This image is saved after the loop has reached all pixels.
public void run() {
// TODO Auto-generated method stub
int part =original.getWidth()/threadCount;
greyscale = new BufferedImage(part, original.getHeight(),BufferedImage.TYPE_BYTE_GRAY);
int x=0;
try{for(int i=threadNumber*part; i<part*(threadNumber+1); i++)
{
for(int j=0; j<original.getHeight(); j++)
{
// Get pixels
int rgb = original.getRGB(i, j);
int a = (rgb>>24)&0xff;
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = (rgb & 0xFF);
int avg = (r + g + b) / 3;
int gray = colorToRGB(a, avg, avg, avg);
greyscale.setRGB(x, j, gray);
} x++;
}}
finally{
saveImage(greyscale, threadNumber);
}
}
public void start(){
}
private static int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red; newPixel = newPixel << 8;
newPixel += green; newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
static void saveImage(BufferedImage r,int threadNumber){
try {
ImageIO.write(r, "png",new File("blackwhiteimageshared"+threadNumber+".png") );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This Code is around two to three times faster than going through every pixel in a loop in one thread.
Would the Producer Consumer Pattern be a good method to change the Code to a state that after the execution i have one monochromatic image instead of 4 parts in a reasonable time?
I have a GUI class which at the click of a button creates and executes a SwingWorker subclass. The SwingWorker class holds a reference to the main one to tell it to update a progress bar. The SwingWorker class instantiates the ExecutorService.FixedThreadPool and submits a number m Callable subclass that returns an ArrayList. When run, the Mac Activity Monitor records n * initial memory where n is the number of threads performed so far, and the process takes a large % of the cpu. The effect of running on 1 thread vs 4 or even 8 with m > n is also a measly 10% gain in speed if any. When creating a new Callable (subclass named DetectFruitTask) with a number of parameters passed in, am I creating a strong reference to it that makes the GC keep it in play?
Here is the one line that might be of concern (note I am not keeping a reference to the returned Callable object and it still causes the memory overload):
executor.submit(new FruitDetectTask((int[])stack.getProcessor(i).getPixels(), sobel, width, height, lumaWeight, sdWeight, threshold));
And here is the actual Callable:
public class FruitDetectTask implements Callable<ArrayList<FruitObject>> {
private int[] pixels;
private float[][] sobel;
private float lumaWeight;
private float sdWeight;
private int width;
private int height;
private float threshold;
public FruitDetectTask(int[] pixels, float[][] sobel, int width, int height, float lumaWeight, float sdWeight, float threshold) {
this.pixels = pixels;
this.sobel = sobel;
this.width = width;
this.height = height;
this.lumaWeight = lumaWeight;
this.sdWeight = sdWeight;
this.threshold = threshold;
}
#Override
public ArrayList<FruitObject> call() throws Exception {
float[] edgeIntensities = EdgeDetector.calculateEdgeIntensities(pixels, sobel, width, height, lumaWeight, sdWeight);
byte[] edges = new byte[edgeIntensities.length];
for (int j = 0; j < edgeIntensities.length; j++) {
if (edgeIntensities[j] > threshold) {
edges[j] = (byte)0;
} else {
edges[j] = (byte)255;
}
}
ArrayList<FruitObject> fruits = FruitDetector.detect(edges, width, height);
return fruits;
}
}
I am having static BufferedImage in the threads and letting each thread modify some sections of the image. The processing is extremely independent as each pixel is done separately, yet the sequential version is faster how could I fix that?
edit 1: here how the code looks like
public static void main(String[] args) throws IOException, InterruptedException {
long startime, endtime;
long Time;
startime = System.currentTimeMillis();
//also tried to use nano
WorkingThread T1 = new WorkingThread("input.jpg");
WorkingThread T2 = new WorkingThread();
WorkingThread T3 = new WorkingThread();
WorkingThread T4 = new WorkingThread();
T1.start();
T2.start();
T3.start();
T4.start();
T1.join();
T2.join();
T3.join();
T4.join();
endtime = System.currentTimeMillis();
Time = endtime - startime;
System.out.println("The time consumed in miliseconds is " + Time);
}
public class WorkingThread extends Thread {
public static BufferedImage img;
public static int p;
public int nb;
public static int width, height;
public WorkingThread(String file) throws IOException {
File f = new File(file);
img = ImageIO.read(f);
width = img.getWidth();
height = img.getHeight();
p = 1;
nb = 0;
}
public WorkingThread() {
nb = p;
p++;
}
public void run() {
int start=nb*height/p;
int end = (nb + 1) * height/p;
//the image will be split according to y axis in this case
for(y=start; y < end ; y++) {
for(x =0; x<width; x++) {
pixel = img.getRGB(x, y);
//processing
img.setRGB(x, y, pixel);
}
}
}
As the comments have already pointed out, the flaw in your benchmark is that the overhead of the thread setup and teardown is larger than the time it actually takes to execute your code sequentially.
By inserting some silly code that takes a lot of time, like the below:
//processing
for (int i = 0; i < 1000; i++) {
pixel = ((~pixel ^ pixel) | pixel) & pixel;
}
...inside the for x/y loop and increasing the max value of i, you'll see that eventually the multithreaded version will be faster than the sequential one.
PS: I used an image that is roughly 2500 x 3300 pixels.
So, as the title reads I am trying to add offsets to my java game. I was given a tip by a friend that I need to minus the offset from where I render the tiles onto my screen.
So I created a random world generator and did the offset thing, but I ran into a problem.
My Code:
public void generateMap(Graphics g) {
block = seed.nextInt(2);
//Render Dirt
if(block == 0) {
g.drawImage(Assets.dirt, x - GameState.xOffset, y - GameState.yOffset, null);
x += 32;
}
//Render Grass
if(block == 1) {
g.drawImage(Assets.grass, x - GameState.xOffset, y - GameState.yOffset, null);
x += 32;
}
//Check Where the X is
if(x > xFinish) {
if(y < yFinish) {
x = xStart;
y += 32;
}
}
}
looks simple enough right? after I do that I create code to add one to the offset every time I loop around:
public void tick() {
xOffset += 1;
}
So after that is done I run it but it does this:
is there any simple way I can fix this so that it appears that the screen "scrolls" to the left?
Is there any simple way I can fix this...
Probably not. Games are complicated. Don't let that dissuade you.
You are generating your game world and drawing in the same methods - you don't want to do this. Separation of responsibility is very important - you don't want a whole bunch of code in one spot doing the same thing. In this case, the functionality to generate the world and the drawing code need to be split.
For the world generation, generate the game world once, and persist it to storage using whatever format you like. Keep this away from the drawing code - it has no place there.
For representing blocks in your world, consider something like this:
class Block {
public BlockType getType() {
return type;
}
public int getxPosition() {
return xPosition;
}
public int getyPosition() {
return yPosition;
}
// hashCode(), equals(), etc omitted, they should be implemented
public static enum BlockType {
Dirt(Assets.dirt),
Grass(Assets.grass);
private final BufferedImage image;
BlockType(BufferedImage image) {
this.image = image;
}
public BufferedImage getImage() {
return image;
}
}
private final BlockType type;
private final int xPosition;
private final int yPosition;
private Block(BlockType type, int xPosition, int yPosition) {
this.type = type;
this.xPosition = xPosition;
this.yPosition = yPosition;
}
public static Block getInstance(BlockType type, int xPosition, int yPosition) {
return new Block(type, xPosition, yPosition);
}
}
You can then use Block.getInstance() to generate a map once, like this:
class GameState {
private final int WORLD_SIZE = 1024;
private Block[][] _world = new Block[WORLD_SIZE][WORLD_SIZE];
private static Random seed = new Random();
public void generateMap() {
int blockTypeLength = Block.BlockType.values().length;
for (int x = 0; x < WORLD_SIZE; x++) {
for (int y = 0; y < WORLD_SIZE; y++) {
int blockType = seed.nextInt(blockTypeLength);
_world[x][y] = Block.getInstance(Block.BlockType.values()[blockType], x, y);
}
}
}
public Block[][] getMap() {
return _world; // not thread safe, shares internal state, all the usual warnings
}
This obviously isn't the only way to generate a world - you would probably generate a world and save, then load from disk in later games (unless it was a short lived game - I don't know, that's your call).
Once you've got the world sorted out, you'd move on to a different module that would handle drawing. Assume GameState has two fields playerX and playerY that represent the player's coordinates in the game world (note: direct fields like this are bad practice, but used to simplify this example):
public void paintComponent(Graphics g) {
super.paintComponent(g);
Block[][] screen = new Block[16][16]; // declare a screen buffer to draw
// Assumes player is in the center of the screen
int screenRadiusX = GameFrame.Assets.SCREENBOUNDS_X / 2 / blockSize;
int screenRadiusY = GameFrame.Assets.SCREENBOUNDS_Y / 2 / blockSize;
for (int x = state.playerX - 8, xS = 0; x < state.playerX + 8; x++, xS++) {
for (int y = state.playerY - 8, yS = 0; y < state.playerY + 8; y++, yS++) {
screen[xS][yS] = world[x][y];
}
}
for (int x = 0; x < screen.length; x++) {
for (int y = 0; y < screen.length; y++) {
Block current = screen[x][y];
g.drawImage(current.getType().getImage(),
x * blockSize, // blockSize is the pixel dimension of
y * blockSize,
null
);
}
}
}
If this helps, then great! I'm glad I was able to help. If not, or if some ideas are still unclear, then I would consider perhaps running through a tutorial or book that walks you through making a game. Don't forget to learn the platform you're coding on during such a process.
I'm quite new to java, and I'm going to need some help here:
package com.game.libs;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class Animation {
private int speed = 0; // defines in how many ticks the animation should go to the next frame
private int amountOfFrames = 0; //amount of frames in the animation
private int index = 0; //time value used in the method runAnimation()
private int currentFrameNumber = 0; //the number of the current frame
private BufferedImage frames[]; //images in the animation
private BufferedImage currentFrameImage; //current frame's image
//13 frame animation
public Animation(BufferedImage[] img, int fps){
frames = img;
amountOfFrames = img.length-1;
speed = 60/fps;
for (int i=0;i<img.length-1;i++){
this.frames[i] = img[i];
currentFrameNumber = 0;
currentFrameImage = img[0];
}
}
public void runAnimation(){
index++;
if(index > speed){
index = 0;
nextFrame();
}
}
public void nextFrame(){
currentFrameNumber++;
if(currentFrameNumber > amountOfFrames)
currentFrameNumber = 1;
currentFrameImage = frames[currentFrameNumber]; // THIS IS THE LINE WITH THE ERROR
}
public void drawAnimation(Graphics graphics, int x, int y, int offset){
graphics.drawImage(currentFrameImage, x - offset, y, null);
}
public void setCurrentFrame(int currentFrame){
this.currentFrameNumber = currentFrame;
}
public int getCurrentFrameNumber(){
return currentFrameNumber;
}
public int getFps(){
return speed;
}
public void setFps(int fps){
this.speed = 60/fps;
}
public void setFrames(BufferedImage[] img){
this.frames = img;
amountOfFrames = img.length;
}
public BufferedImage[] getFrames(){
return frames;
}
}
the error that im getting is array index out bounds. in line 38 (nextFrame method, its in the code)
I've encountered this error before, and I know how to (and tried) to fix it but it says 1 and even 0 are out of bounds...
Plox help, I know this is vague :(, but i tried to make my question (and the code) clear.
remember, im new to java, have had experience with waaaaaaay easier languages/engines but understand quite a bit.
Do note that Java arrays are indexed starting at 0, so it is strange (but not wrong) that in nextFrame() you reset currentFrameNumber to 1 instead of 0 when it runs over.
Also, it's pretty redundant to use amountOfFrames to control the iteration count. The usual Java idioms involve using the array .length directly, maybe
if(currentFrameNumber >= frames.length) {
currentFrameNumber = 0;
}
None of that really explains the exception you get, though, so there must be more to it.
Or something else to it: perhaps the class that is throwing the exception was not compiled from the same version of the code that you present.