After reading the source code, I think should be the first greatest element will be found according to the collection order.
We can check out the source code of the Stream.max(Comparator<? super T> comparator), the implementation class is ReferencePipeline.max
    @Override
    public final Optional<P_OUT> max(Comparator<? super P_OUT> comparator) {
        return reduce(BinaryOperator.maxBy(comparator));
    }
that you can see, when you call the Stream.max, you mean call the Stream.reduce(BinaryOperator<P_OUT> accumulator)
And look at the source code of BinaryOperator.maxBy(comparator)
    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
    }
It's clear, when a equals b, it returns a. So when there are multiple "greatest/lowest" elements in a Stream, the "greatest/lowest" element should be the first "greatest/lowest" element according to the collection order
There is a example at blew, just for your reference.
        List<Student> list = Arrays.asList(new Student("s1", 1), new Student("s2", 5), new Student("s3", 3), new Student("s4", 5));
        // it should be student of 's2'
        list.stream().max(Comparator.comparing(Student::getScore));
        // it should be student of 's4'
        list.stream().reduce((a, b) -> Comparator.comparing(Student::getScore).compare(a, b) > 0 ? a : b);