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() { d.fun(Thread.currentThread().getId()); }
}

class Demo {
    static long f=0;
    synchronized void fun(long id) {
        for(int i=1; i<3; i++){
            System.out.println(id);
                Thread.yield();
                } 
            }
}

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.