public class Thread8 implements Runnable {
    Demo d;

    public static void main(String r[]) {
        new Thread8().disp(); }

    void disp() {
        d = new Demo();
        new Thread(new Thread8()).start();
        new Thread(new Thread8()).start();

    public void run() {; }

class Demo {
    static long f=0;
    synchronized void fun(long id) {
        for(int i=1; i<3; i++){

The program compiles properly but gives a NullPointerException. Why?

Why did it not give a compile error for using a non-static reference variable d [Demo d] in static context i.e. in void disp()?

disp() is not static, so d isn't being used in a static context. If you did use it in a static context you would get a compiler error.
The NPE exception message will tell you exactly where in your code the NPE happened.

ps: To understand your NPE think about how many instances of Thread8 you are creating, and which one(s) correctly initialise the variable d.