Hey guys, I made a program called random.jar for a friend who wanted something simple that could produce secure passwords and here's the result: Code: package random; import java.util.logging.*; import javax.swing.*; import java.awt.event.*; import java.awt.*; import java.util.Random; public class Jarv extends JFrame implements ActionListener, Runnable { // declare the random object for use later Random r = new Random(); // declare the thread for running later Thread t; // declare variables for use in the thread String alphabetChar = ""; StringBuffer outputStr = new StringBuffer(""); // build text box JTextField strOutput = new JTextField(); JTextField strLength = new JTextField(); JLabel StrLengthLabel = new JLabel(" String Length: "); public Jarv() { // basic window stuff super("Random"); setSize(200, 105); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // panel (layout) for the label and text boxes JPanel textPanel = new JPanel(); BorderLayout bb = new BorderLayout(); textPanel.setLayout(bb); textPanel.add("West", StrLengthLabel); textPanel.add("Center", strLength); textPanel.add("South", strOutput); // make button, add listener, and do panel JPanel buttonPanel = new JPanel(); BorderLayout db = new BorderLayout(); JButton runButton = new JButton("Make String"); runButton.addActionListener(this); buttonPanel.setLayout(db); buttonPanel.add("South", runButton); // make checkbox, add to panel JPanel groupPanel = new JPanel(); BorderLayout xb = new BorderLayout(); groupPanel.setLayout(xb); groupPanel.add("Center", textPanel); groupPanel.add("South", buttonPanel); // layout BorderLayout flo = new BorderLayout(); setLayout(flo); add("Center", groupPanel); strLength.setText("6"); setVisible(true); } // thread public void run() { // clear the output variables alphabetChar = ""; outputStr.delete(0, outputStr.length()); // begin random string creation loop for (int idx = 0; idx < Integer.parseInt(strLength.getText()); ++idx){ // begin code if nextboolean is chosen as true if (r.nextBoolean() == true) { // do alpha-numeric translation switch (r.nextInt(26)) { case 0: alphabetChar = "a"; break; case 1: alphabetChar = "b"; break; case 2: alphabetChar = "c"; break; case 3: alphabetChar = "d"; break; case 4: alphabetChar = "e"; break; case 5: alphabetChar = "f"; break; case 6: alphabetChar = "g"; break; case 7: alphabetChar = "h"; break; case 8: alphabetChar = "i"; break; case 9: alphabetChar = "j"; break; case 10: alphabetChar = "k"; break; case 11: alphabetChar = "l"; break; case 12: alphabetChar = "m"; break; case 13: alphabetChar = "n"; break; case 14: alphabetChar = "o"; break; case 15: alphabetChar = "p"; break; case 16: alphabetChar = "q"; break; case 17: alphabetChar = "r"; break; case 18: alphabetChar = "s"; break; case 19: alphabetChar = "t"; break; case 20: alphabetChar = "u"; break; case 21: alphabetChar = "v"; break; case 22: alphabetChar = "w"; break; case 23: alphabetChar = "x"; break; case 24: alphabetChar = "y"; break; case 25: alphabetChar = "z"; break; } // if r gave a true value earlier then capitalise the alphabetChar // variable if (r.nextBoolean() == true) { alphabetChar = alphabetChar.toUpperCase(); } // if r gave a false earlier then make a random number 0-9 and store // it in the relevant array slot } else { alphabetChar = Integer.toString(r.nextInt(10)); } outputStr.append(alphabetChar); } // set the random string output field to the string created by the thread strOutput.setText((outputStr.toString())); } // method activated by the button (listener) public void actionPerformed(ActionEvent event) { // run the thread new Thread(this).start(); } // run the Main() class public static void main(String[] args) { Jarv m = new Jarv(); } } Rapidshare: linky I wanted to ask you guys if i've made any blunders or if bits of my code can be optimized further. Feel free to make comments. EDIT: Source code and rapidshare have now been updated due to massive improvements through the use of stringbuffer and correct application of threading.
Not sure about the code, but my friend and I had a protracted row about whether a computer could actually generate a genuine random number. We eventually agreed, after lots of booze, that it couldn't.
your using run() wrong... which seems like an odd thing to say about a function I know by calling run() directly, it is executing in the same thread if you want to start a new thread you need to have something like: new Thread (this).start(); i'm not 100% sure on that... and it looks a bit ugly too but if it runs in its own thread you probably wont need to "limit the cpu" by sleeping also string concatenation is bad think about using a StringBuffer/StringBuilder
The sleeping is just to spread out the cpu usage over a longer period. Would you mind giving a small example of how to have the extra thread run please? I'm going to go look up what concatenation is now Bit of a programming newbie.
again im not 100% sure on the validity on the below, so you'll have to try it with different threads, your computer should be able to stop the run function using up loads of cpu Code: // method activated by the button (listener) public void actionPerformed(ActionEvent event) { //ive removed your cpuVar stuff, but if you want it, put it back // run the thread new Thread(this).start(); } i would also make outputStr, and alphabetChar local to run() they arent used outside it, and with new threads, you'll likely want separate variables for each *Edit* Concatenation is putting two things together e.g. String str = "a"; str += "b"; str = str + "c"; In java, you cant change Strings, so what it is actually doing, is making its own StringBuffer, appending a character, then changing that back to a string every time
Tyvm plugs , i first implemented the stringbuffer like so: (Snippets) Code: (constructor) // declare variables for use in the thread String alphabetChar = ""; StringBuffer outputStr = new StringBuffer(""); (run function) // clear the output variables alphabetChar = ""; outputStr.delete(0, outputStr.length()); outputStr.append(alphabetChar); } // set the random string output field to the string created by the thread strOutput.setText((outputStr.toString())); I then corrected the event code for running a thread as you suggested and the program is one hell of a lot snappier now, before the mouse down visual would hold as the run() function was executed (about a minute or so for a 111111 length string) now the animation is as it should be and it can do a 9999999 length string in about 9 seconds. +rep to your sir!!
no prob also remember that sleep(1) means sleep for 1millisecond (0.001s) 0.001 * 111111 = 111.111 seconds that might account for your speed gain
It only does the sleep when you tick the limit checkbox (that was more of an experiment), i think the real gain was using a stringbuffer , will definitely be using those in the future.
Ah, well the mouse behaving normally is likely due to it being on a different thread to the GUI also, if you click the button twice, your string will be longer than you expect, even though you reset it (because both threads will be adding characters to the same buffer)
Any way to make it only ever run one extra thread? I've been experimenting and can't seem to figure it out.
you can always disable the button at the beginning of the actionPerformed function then get the run() function to enable it will have to make the button a member of your class //to disable runButton.setEnabled(false);
Hmm, some of that massive speed boost seems to be perceived. A 9999999 length string causes too much memory to be used, and a 9199999 length string takes far longer than it appears to and continually adds to the textbox for some reason, instead of making the string and swapping it into the textbox. Edit: with 7 digit string lengths i start to get out of memory errors. The button event code now looks like this: // method activated by the button (listener) public void actionPerformed(ActionEvent event) { new Thread(this).start(); runButton.setEnabled(false); } and on the end of the run() function is this: runButton.setEnabled(true);
it might be a case the GUI can't keep up... try printing a string that is a million characters long to the console, and it will take a while if you are getting exceptions throw for the memory, you can increase the amount of memory the virtual machine uses assuming it is the GUI... if you really need strings that long, and need to copy them, it might be best to put it into a file *edit* just ran your code, and its only slow went I try to move to the end of the output textfield (using the End button) so GUI definitely seems the culprit
I'm thinking the memory error is the string buffer not being big enough, since the vm size in the debugger never reaches it's max. EDIT: That was the problem, fixed it by changing the end of the run() function to this: outputStr.append(alphabetChar); if (outputStr.length() > 100000) { opt = outputStr.toString(); outputStr.delete(0, outputStr.length()); } } // set the random string output field to the string created by the thread strOutput.setText((opt + outputStr.toString())); opt is a String variable.
and if the string length overall is greater than 2 * 100000, you will overwrite your opt that if block will also slow it down somewhat to me its cleaner to increase the memory the VM is allowed to use or even better, put a maximum on the input size - unless you really need strings this long
True, i don't need outputs of this size (or anywhere near this size), but it's a learning experience to experiment . EDIT: it wasn't the vm size, but the maximum amount of data the StringBuffer variable is capable of holding.
apparently, StringBuffer's size starts off small (you can set it high with the constructor) and will keep doubling in size up to some limit involving the VM's memory limit
This is the full out of memory error: Code: Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space at sun.font.GlyphList.ensureCapacity(GlyphList.java:155) at sun.font.GlyphList.setFromChars(GlyphList.java:242) at sun.java2d.pipe.GlyphListPipe.drawChars(GlyphListPipe.java:85) at sun.java2d.pipe.ValidatePipe.drawChars(ValidatePipe.java:160) at sun.java2d.SunGraphics2D.drawChars(SunGraphics2D.java:2843) at sun.swing.SwingUtilities2.drawChars(SwingUtilities2.java:770) at javax.swing.text.Utilities.drawTabbedText(Utilities.java:170) at javax.swing.text.Utilities.drawTabbedText(Utilities.java:89) at javax.swing.text.PlainView.drawUnselectedText(PlainView.java:137) at javax.swing.text.PlainView.drawElement(PlainView.java:96) at javax.swing.text.PlainView.drawLine(PlainView.java:65) at javax.swing.text.PlainView.paint(PlainView.java:288) at javax.swing.text.FieldView.paint(FieldView.java:171) at javax.swing.plaf.basic.BasicTextUI$RootView.paint(BasicTextUI.java:1422) at javax.swing.plaf.basic.BasicTextUI.paintSafely(BasicTextUI.java:722) at javax.swing.plaf.basic.BasicTextUI.paint(BasicTextUI.java:869) at javax.swing.plaf.basic.BasicTextUI.update(BasicTextUI.java:848) at javax.swing.JComponent.paintComponent(JComponent.java:752) at javax.swing.JComponent.paint(JComponent.java:1029) at javax.swing.JComponent.paintToOffscreen(JComponent.java:5124) at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1479) at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1410) at javax.swing.RepaintManager.paint(RepaintManager.java:1224) at javax.swing.JComponent._paintImmediately(JComponent.java:5072) at javax.swing.JComponent.paintImmediately(JComponent.java:4882) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:785) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:713) at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:693) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:125) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:642) at java.awt.EventQueue.access$000(EventQueue.java:85) Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space at sun.font.GlyphList.ensureCapacity(GlyphList.java:155) at sun.font.GlyphList.setFromChars(GlyphList.java:242) at sun.java2d.pipe.GlyphListPipe.drawChars(GlyphListPipe.java:85) at sun.java2d.pipe.ValidatePipe.drawChars(ValidatePipe.java:160) at sun.java2d.SunGraphics2D.drawChars(SunGraphics2D.java:2843) at sun.swing.SwingUtilities2.drawChars(SwingUtilities2.java:770) at javax.swing.text.Utilities.drawTabbedText(Utilities.java:170) at javax.swing.text.Utilities.drawTabbedText(Utilities.java:89) at javax.swing.text.PlainView.drawUnselectedText(PlainView.java:137) at javax.swing.text.PlainView.drawElement(PlainView.java:96) at javax.swing.text.PlainView.drawLine(PlainView.java:65) at javax.swing.text.PlainView.paint(PlainView.java:288) at javax.swing.text.FieldView.paint(FieldView.java:171) at javax.swing.plaf.basic.BasicTextUI$RootView.paint(BasicTextUI.java:1422) at javax.swing.plaf.basic.BasicTextUI.paintSafely(BasicTextUI.java:722) at javax.swing.plaf.basic.BasicTextUI.paint(BasicTextUI.java:869) at javax.swing.plaf.basic.BasicTextUI.update(BasicTextUI.java:848) at javax.swing.JComponent.paintComponent(JComponent.java:752) at javax.swing.JComponent.paint(JComponent.java:1029) at javax.swing.JComponent.paintToOffscreen(JComponent.java:5124) at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1479) at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1410) at javax.swing.RepaintManager.paint(RepaintManager.java:1224) at javax.swing.JComponent._paintImmediately(JComponent.java:5072) at javax.swing.JComponent.paintImmediately(JComponent.java:4882) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:785) at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:713) at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:693) at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:125) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:642) at java.awt.EventQueue.access$000(EventQueue.java:85) BUILD SUCCESSFUL (total time: 24 seconds)