Readers aren't blocked. You'll need to give a test case to justify your assertion.
Here is ours:
SQL> create table t nologging tablespace largets
2 as select d.* from dba_objects d,
3 ( select 1 from dual connect by level <= 400 );
Table created.
SQL>
SQL>
SQL> select count(*) from t;
COUNT(*)
----------
31540400
So we have a 30million row table. In session 1, I am going start a query, and in session 2 I'll modify a column to not null. I'm using "set time on" so you can see the overlap. I've added some cpu cycles to the query via 'sqrt' so that we know it will run *longer* than the the not null operation.
--
-- session 1
--
13:14:16 SQL> set time on
13:14:16 SQL> select max(owner), max(object_id) from t
13:14:16 2 where sqrt(object_id) != 0;
MAX(OWNER)
--------------------------------------------------------
MAX(OBJECT_ID)
--------------
XDB
219941
13:14:33 SQL>
--
-- session 2
--
SQL> set time on
13:14:20 SQL> alter table t modify owner not null;
Table altered.
13:14:30 SQL>
So you can see - the query run before, during and after the modify to not null. And if we look at the session waits for session 1:
13:15:11 SQL> select event, time_waited
13:15:15 2 from v$session_event
13:15:19 3 where sid = sys_context('USERENV','SID');
EVENT TIME_WAITED
---------------------------------------------------------------- -----------
Disk file operations I/O 0
log file sync 1
db file sequential read 1
direct path read 8
SQL*Net message to client 0
SQL*Net message from client 13858
events in waitclass Other 0
there is nothing suggesting a wait on access to the table.