Explain how fine-grained and coarse-grained hardware multithreading maximize CPU utilization by switching between instruction streams to hide memory latency.