Edit: Based on your new description I believe that you're asking the wrong question. If you're using a Executor you should probably define a custom RejectedExecutionHandler rather than modifying the queue. This only works if you're using a ThreadPoolExecutor, but if you're not it would probably be a better idea to modify the Executor rather than the queue.
It's my opinion that it's a mistake to override offer and make it behave like add. Interface methods constitute a contract. Client code that uses blocking queues depends on the methods actually doing what the documentation specifies. Breaking that rule opens up for a world of hurt. That, And it's inelegant.
The add() method on BlockingQueues does that, but they also have an offer() method which is generally a better choice. From the documentation for offer():
Inserts the specified element at the
tail of this queue if it is possible
to do so immediately without exceeding
the queue's capacity, returning true
upon success and false if this queue
is full. This method is generally
preferable to method add(E), which can
fail to insert an element only by
throwing an exception.
This works for all such queues regardless of the specific implementation (ArrayBlockingQueue, LinkedBlockingQueue etc.)
BlockingQueue<String> q = new LinkedBlockingQueue<String>(2);
System.out.println(q.offer("foo")); // true
System.out.println(q.offer("bar")); // true
System.out.println(q.offer("baz")); // false