When you create a Transaction object, it opens a connection and creates an ADO.NET transaction with the isolation level submitted.
When you issue a READ action, that will not block anything, at least not with readcommitted, since the DB will hold shared locks on the read data. This means that multiple threads will read the same data. The second you change something, the row(s) changed are exclusively locked by the DB. This means that another connection can't read the data of these records, until the locks are removed. (unless the query has 'NOLOCK' specified, but the DQE never adds that). Because you first read the data, this can cause that multiple threads read the same data prior to the locking of the rows.
Reads do not create an exclusive lock on a resource, even in a serialized transaction (as far as I know understand SqlServer's docs). See SET TRANSACTION ISOLATION LEVEL documentation in Books Online.
So to prevent other threads from entering a critical section of your code (a section where you manipulate essential values) you have to use a locking mechanism which does lock the code, because you have a sequence of actions, started with a read (which does not lock the resource) and then an update based on what you read (which does lock the resource, but multiple threads can already have read the data).