Проблема потока в Java: у двух потоков с одинаковым приоритетом не должно быть «порядка», верно?

#java #multithreading

Вопрос:

Я практикуюсь в том, как использовать поток на Java. в настоящее время я пытаюсь доказать, что два отдельных потока имеют дело с общими переменными. Я создал класс:

     public class Prac{
        int z = 0;
        public void foo(int i){
            this.z = i;
            System.out.println(Thread.currentThread().getName()   " updated z to "   z);
            System.out.println("current z is "   this.z);
        }
        public static void main(String[] args){
            Prac p = new Prac();

            Thread t1 = new Thread(new MyThread1(p));
            Thread t2 = new Thread(new MyThread2(p));

            t1.start();
            t2.start();
        }

    }
 

а также две нити:

 public class MyThread1 implements Runnable{
    Prac p = null;

    public MyThread1 (Prac p){
        this.p=p;
    }

    public void run(){
        p.foo(1);
    }
}

public class MyThread2 implements Runnable{
    Prac p = null;

    public MyThread2 (Prac p){
        this.p=p;
    }

    public void run(){
        p.foo(2);
    }
}
 

Я думал, что конечное значение z должно быть иногда 1, иногда 2. Однако конечным всегда будет 2. и если я перееду t2.start() раньше t1.start() , конечным всегда будет 1. Я думал, что не должно быть определенного порядка выполнения двух потоков с одинаковым приоритетом, верно? но почему результат не такой, как я ожидал, пожалуйста?

Спасибо

Комментарии:

1. это зависит от системы. Java не делает никаких предположений о том, как ваша конкретная система будет управлять потоками. Если вы можете, попробуйте с Windows, Linux. Затем попробуйте на raspberry pi. Вы, скорее всего, заметите изменения в поведении.

2. Определенного порядка нет, но запуск потока требует времени , поэтому к моменту запуска потока № 2 поток № 1 уже завершен.

3. @Андреас … и запуск потока не означает, что он запущен. Запуск метода run планируется только в какой-то момент в будущем.

4. @spi Да, но поскольку компьютеры в основном многоядерные, второй поток, как правило, запускается сразу после его запуска. Однако Raspberry Pi-отличный пример одноядерного процессора.

5. @Andreas прав (кстати, у pi4 4 ядра), но я просто указывал, что потоковая передача очень зависит от системы, и вы не можете делать предположения о том, что будет выполнено первым только из одного контекста выполнения. Текущая нагрузка также может изменить поведение (напряженная система, скорее всего, задержит выполнение новых потоков, поскольку для этого ей не хватает ресурсов).

Ответ №1:

Я пытаюсь доказать…

Поведение несинхронизированных потоков в Java (и в большинстве других языков программирования) намеренно остается неопределенным. Причина этого в том, что существует разнообразие в дизайне различных многопроцессорных систем, и, оставляя неопределенным определенное поведение, разработчики могут наиболее эффективно работать на любой конкретной аппаратной платформе и ОС.

Но, предоставив разработчикам Java свободу делать что-либо наиболее эффективным способом, они лишили вас возможности доказать что-либо о потоках с помощью тестирования. Программа, которая ведет себя одинаково каждый раз, когда вы запускаете ее на определенной машине в определенный день, может вести себя по-разному на другой машине, в другой ОС, в другой версии той же ОС, в другой JVM, в другой день и т. Д.

Если вы хотите гарантией каких-либо конкретных результатов в многопоточной программы, только так вы можете делать это с помощью документированных механизмов синхронизации и, путем определения того, как ваша программа будет вести себя исходя гарантии, прописаны в главе 17 из спецификации языка Java, о том, что эти механизмы синхронизации будет делать.