0

When I was learning about threadlocal, I was puzzled by its weak reference recycling mechanism, so I have the following test code:

public static void main(String[] args) {
        Car car = new Car(22000, "sliver");
        Entry entry = new Entry(car, new Object());
        int i = 0;

        while (true) {
            if (entry.get() != null) {
                i++;
                System.out.println("Object is alive for " + i + " loops - " + entry);
            } else {
                // Object is alive for 61441 loops - Entry@490d6c15
                // null,java.lang.Object@7d4793a8
                // Object has been collected.
                System.out.println(entry.get() + "," + entry.getValue());
                System.out.println("Object has been collected.");
                break;
            }
        }
    }

class Car {
    private double price;
    private String colour;

    public Car(double price, String colour) {
        this.price = price;
        this.colour = colour;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getColour() {
        return colour;
    }

    public void setColour(String colour) {
        this.colour = colour;
    }
}

class Entry extends WeakReference<Car> {
    Object value;

    Entry(Car k, Object v) {
        super(k);
        value = v;
    }

    public Object getValue() {
        return value;
    }
}

In my computer, it will execute to the else branch after 6W cycles

My question is:

Why entry.get() is return null, there is also a strong reference in front: Car car = new Car(22000, "sliver");

Zed
  • 23
  • 1
  • 7
  • 2
    Aside from anything, extending `WeakReference` seems like a highly dubious thing to do. If you want a Map entry with weak key and strong value, use `Map.Entry, Object>`. – Andy Turner Nov 11 '20 at 09:09
  • 2
    I'd hardly call the local variable that isn't used for anything (after being put into `Entry`) a *strong* reference...try printing out `car` after the `while` loop. – Kayaman Nov 11 '20 at 09:10
  • @AndyTurner I imitated `ThreadLocal.ThreadLocalMap.Entry` – Zed Nov 11 '20 at 09:13
  • @Kayaman Yes! When the car variable is used later, it will not go to the `else branch`. But what I want to ask is, in this example, car is not used, so has the car been recycled? – Zed Nov 11 '20 at 09:17
  • @Kayaman GCROOTs are as follows: . in this example is: `Java Stack Frame` – Zed Nov 11 '20 at 09:25
  • @Kayaman If it is recycled, it is unreachable, but in this example, it is reachable because it has gcroots: `Java Stack Frame`. Is there a problem with my understanding? – Zed Nov 11 '20 at 09:34
  • @Kayaman I can understand it as: Does JIT optimization need not follow reachability analysis? – Zed Nov 11 '20 at 09:40
  • @Kayaman That is, after JIT has looped 6W times, it found that the local variable `car` is only referenced by weakReferences, which can be recycled and optimized, so is it recycled? – Zed Nov 11 '20 at 10:22
  • @Zed what does "6W times" mean? – Andy Turner Nov 11 '20 at 10:33
  • 2
    @AndyTurner according to the comment in the posted code, 6W means 61441, apparently. Not that the exact number matters. It does not only depend on the JIT state, but the memory utilization, i.e. when GC will be triggered. Since the default is a concurrent garbage collector, it’s an unpredictable timing anyway. Run with `-Xcomp -Xmx4M -XX:+UseSerialGC` to get a reproducible small number of iterations… – Holger Nov 11 '20 at 10:51
  • @Holger I'm really just interested in the terminology, because I've just never come across it before, and OP has used it twice. – Andy Turner Nov 11 '20 at 11:03
  • 2
    @AndyTurner perhaps, the abbreviation for “wàn” the Pīnyīn spelling of the Mandarin word for 10,000 (萬)… – Holger Nov 11 '20 at 12:39
  • @AndyTurner 6W means 60,000, i am used to using Chinese abbreviations. – Zed Nov 11 '20 at 16:32
  • @Zed today I learned something new. – Andy Turner Nov 11 '20 at 16:37

0 Answers0