I looked into Bitcoin Core client code, and it seems that there is a lock that allows only one thread to send data (Block, TX, etc.) at a given time point. If this is true, it means that transactions and blocks have to wait in a queue until the previous once are done sending. Am I right?
That's not quite right.
There are two main threads involved in the network code, the network thread and the message handler thread.
The network thread receives data from peers, parses it into messages, and puts those messages on per-peer queue for processing. It only serves one peer at a time, but is not restricted to processing full messages. For example when only 10 kB of a block have been received, it will process those 10 kB, and continue with another peer. When all TCP packets for a particular message have been completed, the full block message is given to the message handler thread.
The message handler thread is what implements the P2P protocol - it knows how to respond to various incoming messages. It works on a single message at a time, but it never needs to wait for incoming messages - the network thread already dealt with that. If a message is to be sent back in response to an incoming one, that again isn't done directly - it's put on another per-peer queue, where the network thread will pick it up and send it out incrementally until it is gone.
So while it is true that the message handler only operates on full messages at a time, it never needs to wait for a message to be received or sent out on the network.