Why select statement requests exclusive locks? In postgres (9.5) select requests exclusive lock. Why?

play=# \x on
Expanded display is on.
play=#   SELECT * FROM pg_locks pl
  LEFT JOIN pg_stat_activity psa
    ON pl.pid = psa.pid
    where
    pl.mode = 'ExclusiveLock'
;


-[ RECORD 1 ]------+---------------------------------
locktype           | virtualxid
database           |
relation           |
page               |
tuple              |
virtualxid         | 7/16
transactionid      |
classid            |
objid              |
objsubid           |
virtualtransaction | 7/16
pid                | 17376
mode               | ExclusiveLock
granted            | t
fastpath           | t
datid              | 1700431
datname            | play
pid                | 17376
usesysid           | 10
usename            | postgres
application_name   | psql
client_addr        | 127.0.0.1
client_hostname    |
client_port        | 54308
backend_start      | 2018-05-07 15:12:30.682069+02
xact_start         | 2018-05-07 15:12:59.513311+02
query_start        | 2018-05-07 15:12:59.513311+02
state_change       | 2018-05-07 15:12:59.513313+02
wait_event_type    |
wait_event         |
state              | active
backend_xid        |
backend_xmin       | 7152428
query              | SELECT * FROM pg_locks pl       +
                   |   LEFT JOIN pg_stat_activity psa+
                   |     ON pl.pid = psa.pid         +
                   |     where                       +
                   |     pl.mode = 'ExclusiveLock'   +
                   | ;
Always consider locktype when analyzing locks.

In this case locktype = virtualxid, i. e. virtual transaction id. This is an identifier that is local for a backend. PostgreSQL uses such identifiers for read-only transactions to save "normal" transaction ids, that are global to all backends. (You can read why it is doing so, although it is not relevant to the question.) For read-write transaction you will have locktype = transactionid instead.

So, this row in pg_locks basically says that a backend process has an exclusive lock on transaction id of the transaction it is currently executing. PostgreSQL uses this lock to allow other transactions to wait for ours transaction to finish. Citing the doc:


  When a process finds it necessary to wait specifically for another
  transaction to end, it does so by attempting to acquire share lock on
  the other transaction's ID (either virtual or permanent ID depending
  on the situation). That will succeed only when the other transaction
  terminates and releases its locks.