If you're familiar with Microsoft Basics (from QBASIC to VB.net), it's the same thing.
If you're not: BY REFERENCE, which is the way things have always been done on mainframes since S/360, will pass an address (a pointer) to the called program; that's the address of the variable you're passing to the called program; BY VALUE (or BY CONTENT) will copy the parameter to a temporary area and pass the address of the temporary area to the called program. Since the called program will receive a copy of your area, changes made by the called program won't have any effect on your original variable.
You can find some examples of this by looking at the compile listing of a program that went thru the CICS pre-compiler (at least from TS 1.x on): calls to CICS modules often mix BY REFERENCE / BY VALUE. Usually program areas are passed by reference while some literals are passed by value.
I.E.
*EXEC CICS ADDRESS CWA (ADDRESS OF CWA-AREA) END-EXEC.
Call 'DFHEI1' using by content x'0202800007020000000000000000
- '0000000000000000f0f9f4f4f5404040' by reference ADDRESS OF
CWA-AREA end-call.
*EXEC CICS SEND MAP ('XXXX')
* MAPSET ('XXXX')
* CURSOR (CURSORE)
* RESP (WS-RESP) FRSET END-EXEC.
Move 'XXXX' to dfhc0070
Move length of XXXXO to dfhb0020
Move 'XXXX' to dfhc0071
Call 'DFHEI1' using by content x'1804f1002700c100001de0040000
- '20f1f0f7f7f7404040' by reference dfhc0070 by reference
CROSAMCO by reference dfhb0020 by reference dfhc0071 by
content x'0000' by content x'0000' by content x'0000' by
reference CURSORE end-call
IMHO: if you've got recurring strings to pass to called programs (dunno, like "YMD/DMY" or "OPEN"/"CLOSE" or whatever) you may want to try BY VALUE/BY CONTENT; otherwise I wouldn't bother. I guess IBM introduced them (together with RETURNING) for some POSIX/UNIX compliance or possibly for compatibility with C/C++. Possibly guys who know more will shed some light on this topic....