atomic
和nonatomic
在财产声明中的含义是什么?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者之间的操作差异是什么?
答案 0 :(得分:1721)
最后两个是相同的; “atomic”是默认行为(请注意,它实际上不是关键字;仅在没有的情况下指定 - nonatomic
atomic
被添加为关键字最新版本的llvm / clang)。
假设你是@synthesizing方法实现,原子与非原子会改变生成的代码。如果您正在编写自己的setter / getter,则atomic / nonatomic / retain / assign / copy仅仅是建议性的。 (注意:@synthesize现在是LLVM的最新版本中的默认行为。也没有必要声明实例变量;它们也会自动合成,并且会在其名称前加上_
以防止意外直接访问)。
使用“atomic”,合成的setter / getter将确保始终从getter返回整个值或由setter设置,无论其他任何线程上的setter活动如何。也就是说,如果线程A位于getter的中间,而线程B调用setter,则实际可行的值 - 很可能是自动释放的对象 - 将返回给A中的调用者。
在nonatomic
中,没有做出这样的保证。因此,nonatomic
比“原子”快得多。
不做的“原子”是对线程安全做出任何保证。如果线程A与线程B同时调用getter并且C调用具有不同值的setter,则线程A可以获得返回的三个值中的任何一个 - 在调用任何setter之前的值或者传递给setter的任一值在B和C中。同样,对象最终可能会得到B或C中的值,无法分辨。
确保数据完整性 - 多线程编程的主要挑战之一 - 是通过其他方式实现的。
添加到此:
单个属性的 atomicity
在多个依赖属性发挥作用时也无法保证线程安全。
考虑:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
在这种情况下,线程A可以通过调用setFirstName:
然后调用setLastName:
来重命名对象。在此期间,线程B可以在线程A的两个调用之间调用fullName
,并将接收与旧的姓氏一起使用的新名字。
要解决此问题,您需要交易模型。即一些其他类型的同步和/或排除,允许在更新依赖属性时排除对fullName
的访问。
答案 1 :(得分:351)
这在Apple的documentation中有解释,但下面是一些实际发生的例子。请注意,没有“atomic”关键字,如果未指定“nonatomic”,则属性为atomic,但明确指定“atomic”将导致错误。
//@property(nonatomic, retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
现在,原子变体有点复杂:
//@property(retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}
- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[userName_ retain];
[userName release];
userName = userName_;
}
}
基本上,原子版本必须采取锁定以保证线程安全,并且还会碰撞对象的引用计数(以及自动释放计数以平衡它),以便保证对象存在对象,否则如果另一个线程正在设置该值,则存在潜在的竞争条件,导致引用计数降至0。
实际上,根据属性是标量值还是对象,以及如何保留,复制,只读,非原子等交互,实际上存在大量不同的变体。一般来说,属性合成器只知道如何为所有组合做“正确的事情”。答案 2 :(得分:160)
答案 3 :(得分:131)
理解差异的最佳方法是使用以下示例。
假设存在一个名为“name”的原子字符串属性,如果从线程A调用[self setName:@"A"]
,则从线程B调用[self setName:@"B"]
,并从线程C调用[self name]
,然后不同线程上的所有操作都将按顺序执行,这意味着如果一个线程正在执行setter或getter,那么其他线程将等待。
这使得属性“name”读/写安全,但如果另一个线程D同时调用[name release]
,则此操作可能会导致崩溃,因为此处不涉及setter / getter调用。这意味着对象是读/写安全的(ATOMIC),但不是线程安全的,因为另一个线程可以同时向对象发送任何类型的消息。开发人员应确保此类对象的线程安全。
如果属性“name”是非原子的,那么上面例子中的所有线程--A,B,C和D将同时执行,产生任何不可预测的结果。在原子的情况下,A,B或C中的任何一个将首先执行,但D仍然可以并行执行。
答案 4 :(得分:110)
这个问题的其他优秀答案已经很好地定义了语法和语义。由于执行和性能不详细,我将添加我的答案。
这3个之间的功能差异是什么?
我一直认为原子作为一个非常好奇的默认。在抽象层面,我们致力于将类的原子属性用作实现100%线程安全性的工具,这是一个极端情况。对于真正正确的多线程程序,程序员的干预几乎肯定是必需的。同时,性能特征和执行还没有详细说明。多年来编写了一些重度多线程的程序后,我一直在宣称我的属性为nonatomic
,因为原子对任何目的都不合理。在讨论原子和非原子属性this question的细节时,我做了一些分析,遇到了一些奇怪的结果。
<强>执行强>
确定。我想要澄清的第一件事是锁定实现是实现定义和抽象的。路易斯在他的例子中使用@synchronized(self)
- 我已经将此视为混淆的常见原因。实现实际使用@synchronized(self)
;它使用对象级旋转锁。路易斯的插图对于使用我们都熟悉的结构的高级插图是有益的,但重要的是要知道它不使用@synchronized(self)
。
另一个区别是原子属性将保留/释放你的对象在getter中的循环。
<强>性能强>
这是有趣的部分:在某些情况下,使用无争议(例如单线程)案例中的原子属性访问的性能确实非常快。在不太理想的情况下,使用原子访问的成本可能是nonatomic
开销的20倍以上。虽然使用7个线程的 Contested 情况对于三字节结构(2.2 GHz Core i7四核,x86_64)来说慢了44倍。三字节结构是一个非常慢的属性的例子。
有趣的注意事项:三字节结构的用户定义访问器比合成的原子访问器快52倍;或84%的合成非原子访问者的速度。
有争议案件中的物品也可超过50次。
由于实施中的优化和变化的数量,在这些环境中测量实际影响是非常困难的。您可能经常会听到“信任它,除非您分析并发现它是一个问题”。由于抽象级别,实际上很难衡量实际影响。从配置文件收集实际成本可能非常耗时,并且由于抽象,非常不准确。同样,ARC vs MRC可以产生很大的不同。
让我们退后一步,不专注于财产访问的实施,我们将包括像objc_msgSend
这样的常见嫌疑人,并检查一些真实世界的高级别结果在无争议的案例中调用NSString
getter(以秒为单位的值):
正如您可能已经猜到的那样,引用计数活动/循环是原子学和ARC下的重要贡献者。你也会看到有争议的案件有更大的不同。
虽然我密切关注性能,但我仍然说语义优先!。同时,性能是许多项目的低优先级。但是,了解您使用的技术的执行细节和成本肯定不会受到伤害。您应该根据自己的需要,目的和能力使用正确的技术。希望这可以节省您几个小时的比较,并帮助您在设计程序时做出更明智的决定。
答案 5 :(得分:93)
原子 =线程安全
非原子 =没有线程安全
如果实例变量在从多个线程访问时行为正确,则它们是线程安全的,无论运行时环境是否调度或交错执行这些线程,并且在调用时没有其他同步或其他协调代码。
如果线程更改了实例的值,则更改的值可用于所有线程,并且一次只能有一个线程更改该值。
atomic
:如果要在多线程环境中访问实例变量。
atomic
的含义:没有nonatomic
那么快,因为nonatomic
在运行时不需要任何看门狗工作。
nonatomic
:如果实例变量不会被多个线程更改,您可以使用它。它提高了性能。
答案 6 :(得分:67)
我发现原子和非原子属性here的解释非常好。以下是相同的相关文字:
'原子'意味着它无法分解。 在OS /编程术语中,原子函数调用是一个不能被中断的函数 - 整个函数必须执行,并且不会被操作系统通常的上下文切换换出CPU直到它完成。如果您不知道:由于CPU一次只能执行一项操作,操作系统会在很短的时间内将CPU的访问权限转移到所有正在运行的进程,以提供幻觉多任务处理。 CPU调度程序可以(并且确实)在执行过程中的任何时刻中断进程 - 即使在函数调用期间也是如此。因此,对于更新共享计数器变量的操作,其中两个进程可以尝试同时更新变量,它们必须“原子地”执行,即每个更新操作必须完全完成才能将任何其他进程交换到CPU。
所以我猜测在这种情况下原子意味着属性读取器方法不能被中断 - 实际上意味着方法读取的变量不能在中途改变它们的值,因为其他一些线程/调用/ function被交换到CPU上。
因为atomic
变量不能被中断,所以它们在任何一点包含的值都是(线程锁定)保证未损坏,但是,确保此线程锁可以访问他们慢了。另一方面,non-atomic
变量没有这样的保证,但确实提供了更快捷的访问权限。总而言之,当你知道多个线程不会同时访问你的变量并加快速度时,请使用non-atomic
。
答案 7 :(得分:65)
在阅读了这么多文章后,Stack Overflow发布并制作演示应用程序以检查变量属性属性,我决定将所有属性信息放在一起:
atomic
//默认nonatomic
strong = retain
//默认weak = unsafe_unretained
retain
assign
//默认unsafe_unretained
copy
readonly
readwrite
//默认在文章 Variable property attributes or modifiers in iOS 中,您可以找到所有上述属性,这肯定会对您有所帮助。
<强> atomic
强>
atomic
表示只有一个线程访问变量(静态类型)。atomic
是线程安全的。atomic
是默认行为示例:
@property (retain) NSString *name;
@synthesize name;
<强> nonatomic
强>
nonatomic
表示多线程访问变量(动态类型)。nonatomic
是线程不安全的。nonatomic
不是默认行为。我们需要在属性属性中添加nonatomic
关键字。示例:
@property (nonatomic, retain) NSString *name;
@synthesize name;
答案 8 :(得分:52)
最简单的回答:你的第二个例子之间没有区别。默认情况下,属性访问器是原子的。
非垃圾收集环境中的原子访问器(即使用retain / release / autorelease时)将使用锁来确保另一个线程不会干扰正确设置/获取值。
有关更多信息以及创建多线程应用时的其他注意事项,请参阅Apple的Objective-C 2.0文档的“Performance and Threading”部分。
答案 9 :(得分:52)
Atomic保证以原子方式访问属性。例如。它总是返回一个完全初始化的对象,一个线程上的任何属性的get / set必须在另一个线程访问它之前完成。
如果您想象同时在两个线程上发生以下功能,您可以看到为什么结果不会很漂亮。
-(void) setName:(NSString*)string
{
if (name)
{
[name release];
// what happens if the second thread jumps in now !?
// name may be deleted, but our 'name' variable is still set!
name = nil;
}
...
}
优点: 每次返回完全初始化的对象使其成为多线程情况下的最佳选择。
缺点: 性能上升,使执行速度变慢
与Atomic不同,它不能确保每次都完全初始化对象返回。
优点: 执行速度极快。
缺点: 多线程情况下垃圾值的可能性。
答案 10 :(得分:31)
Atomic意味着只有一个线程访问变量(静态类型)。 Atomic是线程安全的,但速度很慢。
Nonatomic意味着多个线程访问变量(动态类型)。 Nonatomic是线程不安全的,但速度很快。
答案 11 :(得分:14)
Atomic 线程安全,缓慢并且保证良好(不保证)只提供锁定值,无论是尝试通过同一区域访问的线程数。使用atomic时,在此函数内部编写的一段代码将成为临界区的一部分,一次只能执行一个线程。
它只保证线程安全;它并不保证。 我的意思是你为你的汽车聘请专家司机,但它不能保证汽车不会遇到意外。但是,概率仍然是最轻微的。
原子 - 它无法分解,因此预期结果。使用非原子 - 当另一个线程访问内存区域时,它可以修改它,因此结果是意外的。
代码谈话:
Atomic使得属性线程的getter和setter安全。例如,如果你写了:
self.myProperty = value;
是线程安全的。
[myArray addObject:@"Abc"]
不是线程安全的。
答案 12 :(得分:12)
没有这样的关键字“原子”
@property(atomic, retain) UITextField *userName;
我们可以使用上面的
@property(retain) UITextField *userName;
请参阅Stack Overflow问题 I am getting issues if I use @property(atomic,retain)NSString *myString 。
答案 13 :(得分:11)
默认是atomic
,这意味着无论何时使用该属性,它确实会降低性能,但它是线程安全的。 Objective-C的作用是设置一个锁,只要实际的线程可以访问变量,只要执行setter / getter。
具有ivar _internal的属性的MRC示例:
[_internal lock]; //lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;
所以最后两个是相同的:
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName; // defaults to atomic
另一方面,nonatomic
不会为您的代码添加任何内容。因此,如果您自己编写安全机制,那么它只是线程安全的。
@property(nonatomic, retain) UITextField *userName;
根本不必将关键字写为第一个属性属性。
不要忘记,这并不意味着整个属性是线程安全的。只有setter / getter的方法调用才是。但是如果你使用一个setter,然后使用2个不同的线程同时使用一个getter,那么它也可能被破坏了!
答案 14 :(得分:9)
原子(默认)
Atomic是默认设置:如果您没有输入任何内容,那么您的属性就是 原子。如果您尝试读取,则保证原子属性 它,你会得到一个有效的价值。它没有任何保证 关于那个价值可能是什么,但你会得到好的数据,而不是 只是垃圾记忆。这可以让你做的就是你有多个 线程或指向单个变量的多个进程,一个 线程可以读取,另一个线程可以写入。如果他们达到同样的目标 时间,读者线程保证获得两个值之一: 要么在改变之前要么在改变之后。什么原子不 给你任何关于你这些价值观的保证 可能会。原子通常与线程安全相混淆, 这是不正确的。您需要保证线程安全 其他方法。但是,原子将保证,如果你试图阅读, 你得到了一些价值。
非原子
另一方面,正如你可能猜到的那样,非原子,只是意味着, “不要做那些原子的东西。”你失去的是保证你 总能找回一些东西。如果你试着在中间阅读 写,你可以找回垃圾数据。但是,另一方面,你走了 快一点因为原子属性必须做一些魔术 为了保证你会得到一个值,它们会慢一些。如果 这是一个你经常访问的属性,你可能想放弃 直到非原子,以确保你不会产生这种速度 罚。
在此处查看更多内容:https://realm.io/news/tmi-objective-c-property-attributes/
答案 15 :(得分:8)
如何声明:
因为原子是默认的,
@property (retain) NSString *name;
AND在实施文件中
self.name = @"sourov";
假设与三个属性相关的任务是
@property (retain) NSString *name;
@property (retain) NSString *A;
@property (retain) NSString *B;
self.name = @"sourov";
所有属性并行工作(如异步)。
如果你打电话给#34;姓名&#34;来自主题 A ,
同时拨打电话
[self setName:@"Datta"]
来自主题 B ,
现在如果* name属性是非原子的那么
这就是为什么非原子被称为线程不安全但是由于并行执行它的性能很快
现在如果* name属性是原子的
这就是为什么原子被称为线程安全 和 这就是为什么它被称为读写安全
此类情况操作将连续执行。 效果不佳
- Nonatomic表示多线程访问变量(动态类型)。
- Nonatomic是线程不安全的。
- 但效果很快
- 非原子不是默认行为,我们需要在属性属性中添加非原子关键字。
对于In Swift 确认Swift属性在ObjC意义上是非原子的。一个原因是你要考虑每个属性的原子性是否足以满足你的需求。
参考:https://forums.developer.apple.com/thread/25642
了解更多信息,请访问网站 http://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.html
答案 16 :(得分:8)
在讨论@property的属性之前,你应该知道@property的用途是什么。 @property提供了一种定义类要封装的信息的方法。如果使用@property声明对象/变量,那么导入其类的其他类可以访问该对象/变量。 如果在头文件中使用@property声明一个对象,则必须在实现文件中使用@synthesize对其进行合成。
示例:
.h class
@interface ExampleClass : NSObject
@property (nonatomic, retain) NSString *name;
@end
.m class
@implementation ExampleClass
@synthesize name;
@end
现在编译器将合成名称的访问器方法。
ExampleClass *newObject=[[ExampleClass alloc]init];
NSString *name1=[newObject name]; // get 'name'
[obj setName:@“Tiger”];
@property的属性列表: 原子。 非原子。 保留。 复制。 只读。 读写。 分配。 强。
atomic:这是默认行为。如果一个对象被声明为原子,那么它就变成了线程安全的。线程安全意味着,在该类的特定实例中只有一个线程可以控制该对象。
示例:
@property NSString *name; //by default atomic
@property (atomic)NSString *name; // explicitly declared atomic
非原子的:它不是线程安全的。您可以使用非原子属性属性来指定合成访问器直接设置或直接返回值,而不保证如果从不同线程同时访问相同的值会发生什么。因此,访问非原子属性比原子属性更快。
@property (nonatomic)NSString *name;
retain:当属性是指向对象的指针时是必需的.setter方法将增加对象的保留计数,以便它将占用autorelease池中的内存。
@property (retain)NSString *name;
复制:如果使用复制,则不能使用retain。使用该类的副本实例将包含其自己的副本。 即使设置了一个可变字符串并随后进行了更改,该实例也会捕获它在设置时所具有的任何值。不会合成任何setter和getter方法。
@property (copy) NSString *name;
NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];
xyzObj.name = nameString;
[nameString appendString:@"Pizza"];
readonly:如果您不想通过setter方法更改属性,则可以只读取属性readonly。
@property (readonly) NSString *name;
readwrite:是默认行为。您无需明确指定readwrite属性。
@property (readwrite) NSString *name;
assign:将生成一个setter,它直接将值赋给实例变量,而不是复制或保留它。这对于NSInteger和CGFloat等原始类型,或者您没有直接拥有的对象(如委托)最好。
@property (assign) NSInteger year;
@property (nonatomic, strong) AVPlayer *player;
unsafe_unretained:Cocoa和Cocoa Touch中有一些类尚不支持弱引用,这意味着你不能声明弱属性或弱局部变量来跟踪它们。这些类包括NSTextView,NSFont和NSColorSpace等。如果需要对这些类之一使用弱引用,则必须使用不安全的引用。 不安全引用类似于弱引用,因为它不保持其相关对象存活,但如果目标对象被释放,则不会将其设置为nil。
@property (unsafe_unretained) NSObject *unsafeProperty;
答案 17 :(得分:8)
如果您在多线程代码中使用属性,那么您将能够看到非原子属性和原子属性之间的区别。非原子比原子快,原子是线程安全的,而不是非原子的。
Vijayendra Tripathi已经举出了一个多线程环境的例子。
答案 18 :(得分:7)
开始之前:您必须知道内存中的每个对象都需要从内存中释放出来才能使新编写器发生。你不能像在纸上那样简单地写一些东西。您必须首先擦除(dealloc)它,然后您可以写入它。如果擦除完成(或完成一半)并且尚未写入(或半写)并且您尝试阅读它的时刻可能非常有问题!原子和非原子帮助您以不同的方式处理这个问题。
首先阅读this问题,然后阅读Bbum's answer。另外,然后阅读我的总结。
atomic
将始终保证
保留计数是在Objective-C中管理内存的方式。 创建对象时,它的保留计数为1.发送时 一个对象一个保留消息,其保留计数增加1.当 您向对象发送释放消息,其保留计数递减 当您向对象发送自动释放消息时,其保留计数 在未来的某个阶段减少1。如果一个对象保留 count减少到0,它被解除分配。
<强>什么?多线程和thread safety不同吗?
是。多线程意味着:多个线程可以同时读取共享数据,但我们不会崩溃,但它并不能保证您不会读取非自动释放的值。通过线程安全,可以保证您所读取的内容不会自动释放。 我们默认情况下不会使所有内容成为原子的原因是,存在性能成本,并且对于大多数事情来说并不需要线程安全。我们的代码的一些部分需要它,对于那些少数部分,我们需要使用锁,互斥或同步以线程安全的方式编写代码。
<强> nonatomic
强>
是否因为拥有或不拥有自动释放池而崩溃。
允许在“尚未完成的写入或空值”的中间读取,或者不允许并且仅在完全写入值时允许读取。
答案 19 :(得分:4)
原子属性确保保留完全初始化的值,而不管有多少线程在做getter&amp;塞特就可以了。
非原子属性指定合成访问器只是直接设置或返回一个值,而不保证如果从不同的线程同时访问同一个值会发生什么。
答案 20 :(得分:3)
Atomic意味着一次只能有一个线程访问该变量(静态类型)。 Atomic是线程安全的,但速度很慢。
Nonatomic意味着多个线程可以同时访问变量(动态类型)。 Nonatomic是线程不安全的,但速度很快。
答案 21 :(得分:2)
如果您使用的是原子,则表示该线程是安全且只读的。如果您使用非原子,则意味着多个线程访问变量并且线程不安全,但它执行速度快,执行读写操作;这是一种动态类型。
答案 22 :(得分:1)
原子性 原子(默认)
默认为“原子”:如果您不输入任何内容,则您的属性为“原子”。原子属性可以保证,如果您尝试从中读取内容,则将取回有效值。它不能保证该值是多少,但是您将获得良好的数据,而不仅仅是垃圾内存。这允许您执行的操作是,如果您有多个线程或多个进程指向一个变量,则一个线程可以读取而另一个线程可以写入。如果它们同时命中,则保证读取器线程获得两个值之一:更改之前或更改之后。原子不会给您任何保证,您可能会获得其中哪些值。原子通常确实与线程安全混淆,这是不正确的。您需要以其他方式保证线程安全。但是,atomic可以保证,如果您尝试阅读,就会获得某种价值。
非原子
从另一方面来说,您可能会猜到,非原子的意思是“不要做那些原子的事情。”您失去的是保证您总是得到一些东西。如果尝试在写入过程中进行读取,则可能会获取垃圾数据。但是,另一方面,您的运行速度更快。因为原子属性必须做一些魔术才能保证您将获得一个值,所以它们要慢一些。如果您经常访问该属性,则可能希望使用非原子属性,以确保不会造成速度损失。 访问
礼貌https://academy.realm.io/posts/tmi-objective-c-property-attributes/
原子属性属性(原子和非原子)没有反映在相应的Swift属性声明中,但是从Swift访问导入的属性时,Objective-C实现的原子性保证仍然有效。 < / p>
So-如果您在Objective-C中定义了原子属性,则在Swift使用它时它将保持原子性。
礼貌 https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c
答案 23 :(得分:1)
在一行中:
Atomic
是线程安全的。 Nonatomic
是线程不安全的。
答案 24 :(得分:0)
Atomic:使用NSLOCK锁定线程,确保线程安全。
非原子:由于没有线程锁定机制,因此无法确保线程安全。
答案 25 :(得分:0)
为了简化整个混淆,让我们了解互斥锁。
根据名称,互斥锁会锁定对象的可变性。因此,如果对象是由类访问的,则其他类不能访问同一对象。
在iOS中,@sychronise
还提供互斥锁。现在它以FIFO模式运行,并确保流不受共享同一实例的两个类的影响。但是,如果任务在主线程上,请避免使用原子属性访问对象,因为它可能会占用您的UI并降低性能。
答案 26 :(得分:0)
事实是他们使用自旋锁来实现原子属性。代码如下:
static inline void reallySetProperty(id self, SEL _cmd, id newValue,
ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:NULL];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:NULL];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
_spin_lock(slotlock);
oldValue = *slot;
*slot = newValue;
_spin_unlock(slotlock);
}
objc_release(oldValue);
}
答案 27 :(得分:0)
原子属性:-当分配了具有原子属性的变量时,该变量仅具有一个线程访问权限,并且将是线程安全的,并且在性能方面具有良好的表现,将具有默认行为。>
非原子属性:-当分配了原子属性的变量表示其具有多线程访问权限,并且不是线程安全的并且性能缓慢时,将具有默认行为以及何时两个不同的线程希望同时访问变量,这将产生意外的结果。