首页 文章

访问内部类的多个线程

提问于
浏览
2

我创建了3个线程,它们正在访问 ThreadsAroundInnerClasses 外层类的内部类 MyInnerClass .

package com.test;

public class ThreadsAroundInnerClasses {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread(), "THREAD-1");
        Thread t2 = new Thread(new MyThread(), "THREAD-2");
        Thread t3 = new Thread(new MyThread(), "THREAD-3");
        t1.start();
        t2.start();
        t3.start();
    }

    static class MyInnerClass {
        static int counter = 0;
        public void printIt(String threadName) {
            System.out.println("I am inside inner class, counter value is " + ++counter + " and thread name is " + threadName);
        }
    }
}

class MyThread implements Runnable {
    @Override
    public void run() {
        ThreadsAroundInnerClasses.MyInnerClass innerObj = new ThreadsAroundInnerClasses.MyInnerClass();
        innerObj.printIt(Thread.currentThread().getName());
    }
}

在输出中,我可以看到 MyInnerClass 类中的 counter 静态变量没有按顺序更新 .

I am inside inner class, counter value is 1 and thread name is THREAD-1
I am inside inner class, counter value is 3 and thread name is THREAD-2
I am inside inner class, counter value is 2 and thread name is THREAD-3

如果有人可以解释在多线程的情况下如何处理内部类,那将是非常有帮助的?我们可以同步整个内部阶级吗?

在此先感谢您的帮助 .

3 回答

  • 1

    这是一个关于read-then-change和线程可见性的问题

    Read-then-change

    增量首先是读取,然后是添加,然后是回写 . ++countercounter = counter + 1 的简称,因此意味着:"read counter, add one, write the result back to counter" . 这个流可以在另一个线程中间中断:Thread1读取计数器,得到1 - 并被中断 . Thread2读取计数器 - 它's still 1 - adds 1 - and gets interrupted. Thread3 reads counter - it'仍然是1 - ....依此类推 . 这种行为基本上是随机的 . 您可以通过在后台运行其他应用程序来激发不同的输出 .

    Thread visibility

    对于多核架构上的非易失性,非同步变量,不同的线程可能在不同的核上运行,并且核可以将变量缓存在它们的寄存器上 . 这意味着一个线程可能无法看到另一个线程写入变量的内容 - 直到它被提交回内存并且有一个新的写入 .

    同步是创建内存障碍的一种方式 . 系统将保证在下次锁定时可以看到锁内写入的所有内容 . 实际上 - 当您退出synchronized块时,您所做的一切都将被提交到内存中 . 然后输入synchronized块,从内存中读回所有内容 .

    volatile 关键字告诉系统禁止将变量缓存在寄存器中 - 它必须始终在内存中读写 . 这使得每个人都阅读了最新的内容,但由于上述原因,它无法解决您的问题 .

    The easy solution

    解决特定问题的最简单方法是使用AtomicInteger .

    static class MyInnerClass {
        static final AtomicInteger counter = new AtomicInteger(0);
        public void printIt(String threadName) {
            System.out.println("I am inside inner class, counter value is " +
                counter.incrementAndGet() + " and thread name is " + threadName);
        }
    }
    

    这将为您节省同步的所有麻烦 - 它包含在AtomicInteger类中 .

  • 1

    class 是否属于内部阶级是无关紧要的 . 您在此处看到的是预期输出:您的程序中没有任何同步,因此线程调度程序可以在需要时自由切换到其他线程 . 这是一系列可能的操作,这将导致您看到的输出 .

    • T1:递增计数器

    • T1:concaenate

    • T1:打印

    • T3:增量计数器

    • T3:连接

    • T2:增量计数器

    • T2:连接

    • T2:打印

    • T3:打印

    如果你想要计数器增量,连接和打印是一个原子操作,那么你应该确保它在一个独特的锁上同步:

    synchronized MyInnerClass.class {
        System.out.println("I am inside inner class, counter value is " + ++counter + " and thread name is " + threadName);
    }
    
  • 4

    试试这个:

    static class MyInnerClass {
        static int counter = 0;
        public void printIt(String threadName) {
            synchronized(MyInnerClass.class) {
                System.out.println("I am inside inner class, counter value is " + ++counter + " and thread name is " + threadName);
            }
        }
    }
    

    您的计数器是静态的,因此您需要在整个类对象上进行同步 .

相关问题