我创建了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 回答
这是一个关于read-then-change和线程可见性的问题
Read-then-change
增量首先是读取,然后是添加,然后是回写 .
++counter
是counter = 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 .
这将为您节省同步的所有麻烦 - 它包含在AtomicInteger类中 .
class 是否属于内部阶级是无关紧要的 . 您在此处看到的是预期输出:您的程序中没有任何同步,因此线程调度程序可以在需要时自由切换到其他线程 . 这是一系列可能的操作,这将导致您看到的输出 .
T1:递增计数器
T1:concaenate
T1:打印
T3:增量计数器
T3:连接
T2:增量计数器
T2:连接
T2:打印
T3:打印
如果你想要计数器增量,连接和打印是一个原子操作,那么你应该确保它在一个独特的锁上同步:
试试这个:
您的计数器是静态的,因此您需要在整个类对象上进行同步 .