Essentially for each transaction that you want to initiate, you (or more specifically your client) indicate where you got the money from that you want to use for that transaction. These are called the inputs to your transaction. Your recipient (and actually every node on the network) then looks to make sure that you haven't spent that money from that transaction anywhere else. (This is the double spend issue that is referenced in another answer).
It's easy to implement efficiently because every synced bitcoin client has a complete list of all transactions. And they can index those transactions based on the transaction id so that they can very quickly lookup whether a transaction has already been spent or not. Or for that matter whether that transaction exists at all or not.
In other words, if you tried to spend 10 BTC that you didn't really have, you would have to "make up" a fake transaction of where you got that 10BTC from. And any client on the network would instantly detect that your made up transaction didn't exist and refuse to propagate your new transaction.
Actually this is a little different than a double spend problem the way I read it.