代码之家  ›  专栏  ›  技术社区  ›  keeping_it_simple

多线程:线程获得自己的方法副本,但参数是共享的

  •  0
  • keeping_it_simple  · 技术社区  · 10 年前

    我想确认我对此的理解-

    public class Main {
    
        private static int j = 0;
        private int k = 0;
    
        public static void main(String[] args) {
            Main obj = new Main();
            obj.doProcess();
        }
    
        public void doProcess() {
            ExecutorService service = Executors.newFixedThreadPool(10);
            for (int i = 0; i < 4; i++) {
                service.submit(new SingleProcessor());
            }
        }
    
        public static void myStaticMethod() {
            System.out.println("my static method");
            int i = 0;
            i++;
            j++;
            System.out.println("i " + i);
            System.out.println("j " + j);
        }
    
        public void myInstanceMethod() {
            System.out.println("my instance method");
            int i = 0;
            i++;
            k++;
            System.out.println("k " + k);
        }
    
        private class SingleProcessor implements Runnable {
    
            @Override
            public void run() {
                System.out.println("single run starts" + Thread.currentThread().getName());
                myStaticMethod();
                myInstanceMethod();
            }
    
        }
    }
    

    当线程运行时,它会获得自己的方法副本,无论是静态方法还是实例方法——在这些方法中创建的任何变量都是本地的,并且特定于该线程。这就像这个方法的多个“实例”同时被执行一样,内部创建的任何变量都不会被共享(它是本地的)。

    但是,参数(静态或实例)由线程共享。

    所以在上面的例子中- 我是本地的,特定于线程。 j被共享。 k是共享的。

    输出,输出-

    single run startspool-1-thread-1
    single run startspool-1-thread-2
    my static method
    single run startspool-1-thread-3
    my static method
    i 1
    i 1
    j 2
    j 2
    my instance method
    my instance method
    k 1
    k 2
    my static method
    i 1
    j 3
    my instance method
    k 3
    single run startspool-1-thread-4
    my static method
    i 1
    j 4
    my instance method
    k 4
    

    我的理解是否100%正确?有人愿意用更好的话来表达吗?

    谢谢

    3 回复  |  直到 10 年前
        1
  •  1
  •   Jay    10 年前

    如果我没有错,那应该是正确的。

    这是对堆栈与堆的基本理解。堆栈上声明的任何内容(函数中声明的变量)只能在本地使用。堆上声明的变量可以全局访问,也可以由其范围内的任何函数访问。

    因此,如果您有一个线程处理一个函数,那么函数中的所有变量只能在该函数中访问。但是如果您有一个全局变量和两个线程,那么两个线程都可以访问该变量。问题在于,如果它们写入该变量,则必须确保它们不会相互覆盖。

    解决方案是在一个线程对堆变量进行读/写时锁定堆变量,然后在完成时解锁堆变量。

        2
  •  0
  •   mostruash    10 年前

    如果运行下面的代码,您认为会发生什么?您将看到类似的输出,但顺序可能不同。 i 是静态变量并且在静态范围内, j 在方法范围内, k 是的实例变量 Main 。线程也是一样的。作用域与线程的作用相同。您应该阅读内部类。

    public class Main {
    
        private static int j = 0;
        private int k = 0;
    
        public static void main(String[] args) {
            Main obj = new Main();
            obj.doProcess();
        }
    
        public void doProcess() {
            for (int i = 0; i < 4; i++) {
                SingleProcessor sp = new SingleProcessor();
                sp.run();
            }
        }
    
        public static void myStaticMethod() {
            System.out.println("my static method");
            int i = 0;
            i++;
            j++;
            System.out.println("i " + i);
            System.out.println("j " + j);
        }
    
        public void myInstanceMethod() {
            System.out.println("my instance method");
            int i = 0;
            i++;
            k++;
            System.out.println("k " + k);
        }
    
        private class SingleProcessor implements Runnable {
    
            @Override
            public void run() {
                System.out.println("single run starts" + Thread.currentThread().getName());
                myStaticMethod();
                myInstanceMethod();
            }
    
        }
    }
    
        3
  •  -1
  •   JSlain    10 年前

    你说得对。

    静态变量可以作为Singleton在应用程序中插入,无论您有多少线程,它们都将始终引用同一个变量。

    至于实例变量 “k” ,它只在嵌套类不是静态的情况下工作,这意味着 需要 的实例 主要的 能够安装 单处理器 。您的实例 单处理器 会有一个隐藏的变量引用你 主要的 例子就像你要写这个一样:

    public class SingleProcessor implements Runnable {
    
        private Main main;
    
        public SingleProcessor(Main main){
            this.main = main;
        }
    
        @Override
        public void run() {
            System.out.println("single run starts" + Thread.currentThread().getName());
            Main.myStaticMethod();
            this.main.myInstanceMethod();
        }
    
    }
    

    把你所有的 单处理器 相同的 主要的 例子


    所有这些都是危险的,线程可能会获取变量 同时 另一个线程正在修改它。有很多关于线程安全的高级主题。对于简单类型,可以使用原子变量,se Concurrency package JavaDoc .