If you like Quicksilver...
The Apple Blog reviewed Visor from the creator of Quicksilver. Visor keeps the terminal instantly accessible. I'll have to try it.
The Apple Blog reviewed Visor from the creator of Quicksilver. Visor keeps the terminal instantly accessible. I'll have to try it.
I've been looking for a decent scanning application for OS X so I can digitize, organize and shred all of these boxes of paper. The software that came with my HP all-in-one only creates one page PDFs. Useless. I have to use Automator every time I want to concatenate PDFs.
kip looks promising. Scan multiple pages, tag and search PDFs, very slick UI. I can see the tagging leveraging my sloppy habits. You can't beat the price: currently free. Looks like I have a long weekend ahead of me. Maybe I should pick up a multi-page scanner...
Richard Hatch, the first Survivor winner, went to federal prison for failing to pay taxes on his Survivor winnings. Makes sneaking matches onto the island during Survivor All Stars look like a drop in the bucket.
If we get caught, we're not going to white-collar resort prison. No, no, no. We're going to federal POUND ME IN THE ASS prison. --Michael Bolton, Office Space
Hold the politicians accountable. Support Net Neutrality. Visit itsournet.org.
Update: As I've recently discovered, the array-based pattern at the end of this entry not only improves performance, but it can also help you work around a ThreadLocal
bug present in JDK 1.4 and 1.5.
This is the first in what I hope will turn into a series of entries on the core Java libraries and language.
(Digg this.)
Use a thread local variable (where each thread has a separate value) when you want to carry a value along without explicitly passing it from method to method down the call stack, and when appropriate, remember to explicitly clear the value in a finally
block to prevent memory leaks:
ThreadLocal<Context> threadLocal = new ThreadLocal<Context>(); void doSomethingInContext(Context c) { threadLocal.set(c); try { doSomething(); } finally { threadLocal.remove(); } }
Consider whether or not the code which sets the thread local value can be reentered. I often use thread locals purely to test for reentance. If you prohibit reentrance, fail early:
ThreadLocal<Context> threadLocal = new ThreadLocal<Context>(); void doSomethingInContext(Context c) { if (threadLocal.get() != null) throw new IllegalStateException(); threadLocal.set(c); try { doSomething(); } finally { threadLocal.remove(); } }
If you do allow reentrance, you may want to save and restore the existing value. To support multiple reentrance, you need to keep a stack of previous values. Rather than use an explicit stack data structure, we can utilize the thread stack and save some code and overhead:
ThreadLocal<Context> threadLocal = new ThreadLocal<Context>(); void doSomethingInContext(Context c) { Context previous = threadLocal.get(); threadLocal.set(c); try { doSomething(); } finally { threadLocal.set(previous); } }
Thread local access isn't expensive per se, but it's also not so cheap that we want to perform unnecessary lookups in frequently executed code. The following code performs three thread local lookups for the initial call and one lookup for reentrant calls:
ThreadLocal<Context> threadLocal = new ThreadLocal<Context>(); void doSomethingInContext() { 1. Context c = threadLocal.get(); if (c == null) { c = new Context() 2. threadLocal.set(c); try { doSomething(c); } finally { 3. threadLocal.remove(); } } else { doSomething(c); } }
Notice we clean up the Context
instance when we create it but not when it already exists?
By adding a flag to Context
and overridding ThreadLocal.initialValue()
, we can save one lookup and still ensure proper cleanup. The flag tells us whether or not the current invocation is responsible for the cleanup:
ThreadLocal<Context> threadLocal = new ThreadLocal<Context>() { protected Context initialValue() { return new Context(); } }; void doSomethingInContext() { Context c = threadLocal.get(); if (c.isVirgin()) { c.loseVirginity(); try { doSomething(c); } finally { threadLocal.remove(); } } else { doSomething(c); } } class Context { boolean virgin = true; // "new" is taken. public boolean isVirgin() { return virgin; } public void loseVirginity() { this.virgin = false; } }
We can still do better. If we store a wrapper object instead of a direct reference to the Context
, we can reduce the number of thread local lookups in the initial invocation to one, one third of those in our original example. We'll use a single element array as our wrapper object to save us from having to write another class:
ThreadLocal<Context[]> threadLocal = new ThreadLocal<Context[]>() { protected Context[] initialValue() { return new Context[1]; } }; void doSomethingInContext() { Context[] c = threadLocal.get(); if (c[0] == null) { try { c[0] = new Context(); doSomething(c[0]); } finally { c[0] = null; } } else { doSomething(c[0]); } }
If we don't want our ThreadLocal
instance to prevent the garbage collection of the Context
class, we should use an Object[]
instead of a Context[]
. We might want to do this if library code (in the system classpath perhaps) references our thread local variable and a child class loader loads Context
.
Code which depends directly on a ThreadLocal
can be difficult to test (on par with code which depends directly on a static variable). As an alternative, follow dependency injection patterns and inject thread local values into your code.
Warren Jeffs is the brutal tyrant behind America's leading Mormon cult - as well as a prolific polygamist with a penchant for child brides. For two years he has been the target of an FBI manhunt.
Also, are there any plans for an API which would enable me to modify my list programatically? I'd love an OS X dashboard widget and a Google Homepage gadget.
It's incredibly painful. It's too obvious that this man has no idea what the Internet is exactly and no idea about the issues behind Net neutrality. It seems like a miracle that he can even find the crapper.I tried to send Stevens some feedback directly when I first heard his speech, but the email form on his web site timed out. I guess the Internet's tubes were clogged. Way to go, D.