Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/jsf/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程何时访问同一代码?_Java_Multithreading_Thread Safety - Fatal编程技术网

Java 多线程何时访问同一代码?

Java 多线程何时访问同一代码?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我的问题是: 默认情况下,Java程序是否只导致创建一个线程 如果是,并且如果我们创建一个多线程程序,那么多个线程何时访问Java对象的相同代码 例如,我有一个Java程序,它有两个方法-add()和sub()。在什么情况下,2个或更多线程将运行“add()”方法 代码不总是线程安全的吗,因为多个线程将访问代码的不同部分 如果不是,请给出一个线程安全是一个问题的示例程序 取决于实施情况。只有一个线程(“主线程”)将调用publicstaticvoidmain(String[])方法,但这并不意味

我的问题是:

  • 默认情况下,Java程序是否只导致创建一个线程
  • 如果是,并且如果我们创建一个多线程程序,那么多个线程何时访问Java对象的相同代码
  • 例如,我有一个Java程序,它有两个方法-add()和sub()。在什么情况下,2个或更多线程将运行“add()”方法

    代码不总是线程安全的吗,因为多个线程将访问代码的不同部分

    如果不是,请给出一个线程安全是一个问题的示例程序

  • 取决于实施情况。只有一个线程(“主线程”)将调用
    publicstaticvoidmain(String[])
    方法,但这并不意味着其他线程没有为其他任务启动

  • 如果您对线程进行编程,那么它将访问“相同的代码”。我不确定你对“代码部分”的想法是什么,或者两个线程永远不会同时访问同一个“部分”的想法是从哪里来的,但是创建线程不安全的代码是非常简单的

    import java.util.ArrayList;
    import java.util.List;
    
    public class Main {
    
        public static void main(String[] args) throws InterruptedException {
            List<Object> list = new ArrayList<>();
    
            Runnable action = () -> {
                while (true) {
                    list.add(new Object());
                }
            };
    
            Thread thread1 = new Thread(action, "tread-1");
            thread1.setDaemon(true); // don't keep JVM alive
    
            Thread thread2 = new Thread(action, "thread-2");
            thread2.setDaemon(true); // don't keep JVM alive
    
            thread1.start();
            thread2.start();
    
            Thread.sleep(1_000L);
        }
    
    }
    
    import java.util.ArrayList;
    导入java.util.List;
    公共班机{
    公共静态void main(字符串[]args)引发InterruptedException{
    列表=新的ArrayList();
    可运行操作=()->{
    while(true){
    添加(新对象());
    }
    };
    螺纹1=新螺纹(动作“踏板-1”);
    thread1.setDaemon(true);//不要让JVM保持活动状态
    螺纹2=新螺纹(动作“螺纹2”);
    thread2.setDaemon(true);//不要让JVM保持活动状态
    thread1.start();
    thread2.start();
    线程睡眠(1_000L);
    }
    }
    
    ArrayList
    不是线程安全的。上面的代码有两个线程不断尝试将新的
    对象
    添加到同一
    数组列表
    大约一秒钟。这并不能保证,但如果您运行该代码,您可能会看到
    ArrayIndexOutOfBoundsException
    或类似的内容。无论抛出任何异常,
    ArrayList
    的状态都有被破坏的危险。这是因为状态由多个线程更新,没有同步

  • 1) 默认情况下,Java程序是否只导致创建一个线程

    这取决于你的代码在做什么。一个简单的
    System.out.println()
    调用可能只创建一个线程。但是,例如,一旦您打开Swing GUI窗口,至少会有一个其他线程(对用户输入作出反应并负责UI更新的“事件调度程序线程”)

    2) 如果是,并且如果我们创建一个多线程程序,那么多个线程何时访问Java对象的相同代码

    你这方面的误解。对象没有代码。基本上,线程将运行特定的方法;它自己的
    run()。然后线程只执行该方法,以及从该初始方法触发的任何其他方法调用

    当然,在运行该代码时,该线程可能会创建其他对象,或者操纵现有对象的状态。当每个线程只接触一组不同的对象时,就不会出现问题。但是一旦有多个线程处理相同的对象状态,就需要采取适当的预防措施(以避免不确定的行为)。

    不要考虑“代码部分”,要考虑数据所在的位置以及有多少线程正在访问实际数据

    • 局部变量位于使用它们的线程堆栈上,并且是线程安全的,因为它们是每个线程的不同数据“容器”

    • 堆上的任何数据,如实例或静态字段,本质上都不是线程安全的,因为如果有多个线程访问该数据,那么它们可能存在争用

    我们可以更复杂地讨论数据的真实位置,但这个基本的解释应该会让你对发生的事情有一个很好的了解

    下面的代码给出了一个由两个线程共享的实例示例,在本例中,两个线程都在访问相同的数组列表,该列表指向堆中的相同数组数据容器。运行几次,您最终会看到失败。如果你注释掉其中一个线程,它每次都会正常工作,从99开始倒数

    import java.util.ArrayList;
    import java.util.List;
    public class Main {
        public static void main(String[] args) {
            MyRunnable r = new MyRunnable();
            new Thread(r).start();
            new Thread(r).start();
        }
        public static class MyRunnable implements Runnable {
            // imagine this list living out in the heap and both threads messing with it
            // this is really just a reference, but the actual data is in the heap
            private List<Integer> list = new ArrayList<>();
            {  for (int i = 0; i < 100; i++) list.add(i);  }
    
            @Override public void run() {
                while (list.size() > 0) System.out.println(list.remove(list.size() - 1));
            }
        }
    }
    
    import java.util.ArrayList;
    导入java.util.List;
    公共班机{
    公共静态void main(字符串[]args){
    MyRunnable r=新的MyRunnable();
    新线程(r.start();
    新线程(r.start();
    }
    公共静态类MyRunnable实现Runnable{
    //想象一下这个列表存在于堆中,两个线程都在处理它
    //这实际上只是一个引用,但实际数据在堆中
    私有列表=新的ArrayList();
    {for(inti=0;i<100;i++)list.add(i);}
    @重写公共无效运行(){
    而(list.size()>0)System.out.println(list.remove(list.size()-1));
    }
    }
    }
    
    您的问题表明您可能不完全理解“线程”的含义

    当我们学习编程时,他们告诉我们计算机程序是一系列指令,他们告诉我们计算机从某个定义良好的入口点(例如,
    main()
    例程)开始逐个执行这些指令

    好的,但是当我们谈论多线程程序时,仅仅说“计算机”执行我们的代码是不够的。现在我们说线程执行我们的代码。每个线程对它在程序中的位置都有自己的想法,如果两个或多个线程碰巧同时在同一个函数中执行,那么每个线程都有自己的函数参数和局部变量的私有副本

    所以,你问:

    是一个Java程序吗
    class MyRunnable implements Runnable {
        public void run() {
            DoSomeUsefulThing();
            DoSomeOtherThing();
        }
    }
    MyRunnable r = new MyRunnable();
    Thread t = new Thread(r);
    t.start();
    ...
    
    ...
    Thread t = new Thread(r);
    t.start();
    DoSomeUsefulThing();
    ...
    
    class MyDataClass { ... }
    Class MyRunnable implements Runnable {
        private MyDataClass data;
    
        public MyRunnable(MyDataClass data) {
            this.data = data;
        }
    
        public void run() {
            DoSomeUsefulThingWITH(data);
            DoSomeOtherThingWITH(data);
        }
    }
    MyDataClass dat_a = new MyDataClass(...);
    MyDataClass dat_b = new MyDataClass(...);
    MyRunnable r = new MyRunnable(dat_a);
    Thread t = new Thread(r);
    t.start();
    DoSomeUsefulThingWITH(dat_b);