Non-capturing lambda seems to nevertheless capture the enclosing instance

In your lambda expression’s body, you have the anonymous class declaration new Thread() {} and you are not in a static context, so this expression implicitly captures this, which has the same meaning within the lambda expression as outside of it, per JLS §15.27.2, Lambda Body:

Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).

The transparency of this (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.

Since the surrounding context determines the behavior of the anonymous class, you can easily fix the issue by using a static context to create a nested class instead:

import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.function.Supplier;

public class Main {
    public static void main(String[] args) throws Exception {
        write();
    }

    static void write() throws Exception {
        Supplier<Thread> supplier = (Supplier<Thread> & Serializable)() -> new Thread() {};
        new ObjectOutputStream(System.out).writeObject(supplier);
    }
}

Then, no surrounding instance will be captured.

Note that this can be seen as the general idea of lambda expressions, to define functions as expressions having exactly the same meaning as within the context they are written, except for the introduction of function parameters. The generation of an instance of a functional interface is only the vehicle to get this concept into the Java programming language in a compatible and useful way, but not a concept to influence the meaning of the lambda expression.