我正在编写一个多线程程序,正在研究是否应该使用var TableData:Array< String > = Array < String >()
override func viewDidLoad() {
super.viewDidLoad()
splitViewController!.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
UINavigationBar.appearance().barTintColor = UIColor(red: 52.0/255.0, green: 170.0/255.0, blue: 220.0/255.0, alpha: 1.0)
UINavigationBar.appearance().tintColor = UIColor.whiteColor()
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.whiteColor()]
//JSON
let url = NSURL(string:"https://www.kimonolabs.com/api/7flcy3qm?apikey=gNq3hB1j0NtBdAvXJLEFx8JaqtDG8y6Y")!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) { (data, response, error) -> Void in
if error != nil {
print(error)
} else {
if let _ = data {
do {
let jsonString = try NSString.init(contentsOfURL: url, encoding: NSUTF8StringEncoding)
// Create JSON object from data
let json = JSON(data: jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
// Check if array for key "collection2" exists
if let collection2 = json["results"]["collection2"].array {
// Create JSON array from it and loop for each object
for (_, subJson):(String, JSON) in JSON(collection2) {
// Check if dictionary for key "Event" exists
if let event = subJson["Event"].dictionary {
print(event)
}
// Check if string for key "Hasta" exists
if let hasta = subJson["Hasta"].string {
print(hasta)
}
// Check if string for key "Location" exists
if let location = subJson["Location"].string {
print(location)
}
}
}
} catch {
print("In catch block")
}
}
}
}
task.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.TableData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
cell.textLabel?.text = self.TableData[indexPath.row]
return cell
}
}
作为我的布尔标志。关于并发性的文档oracle跟踪并未解释除{:1}之外的任何内容:
不同线程有内存一致性错误 不一致的观点应该是什么相同的数据。
假设这些不一致的视图仅在“写入”操作之后发生是有意义的。但是多久之后呢?
示例1
volatile
由于memory consistency errors
和Thread A: Retrieve flag.
Thread B: Retrieve flag.
Thread A: Negate retrieved value; result is true.
Thread A: Store result in flag; flag is now true.
Thread B: System.out.print(flag) --> false
同时运行,因此打印也可能为true,具体取决于检索时间Thread A
。对于不一致而言,这是完全合理的。
但是描述Thread B
的方式(写入变量不一定反映在其他线程中)听起来也是如此:
示例2
flag
我强烈认为示例2不可能是真的。问题是,只有当 为真时才能看到使用memory consistency errors
来建立Thread A: Retrieve flag.
Thread A: Change retrieved value; result is true.
Thread A: Store result in flag; flag is now true.
//any longer amount of time passes (while Thread A didn't explicitly happen-before Thread B, it obviously did.)
Thread B: Retrieve flag.
Thread B: System.out.print(flag) --> true OR false (unpredictable)
。
如果是真的,为什么会这样呢?如果不是......为什么要使用volatile
?
答案 0 :(得分:5)
了解JVM内存模型最具挑战性的事情之一是,严格来说, timing (即你的挂钟)完全无关紧要。
无论多久(根据您的挂钟)时间在2个独立线程中的两次操作之间经过,如果发生在关系之前,绝对不能保证每个线程在内存中会看到什么。
在您的示例2 中,您提到了一个棘手的部分,
虽然线程A没有明确发生 - 在线程B之前,显然已经。
从上面的描述来看,唯一可以说是显而易见的是,根据您的挂钟测量的时间,某些操作发生以后比其他人。但 并不意味着严格意义上的JVM内存模型中的 关系。
让我展示一组与您上面的示例2的描述兼容的操作(即,根据您的挂钟所做的测量),这可能会导致 true 或 false ,不能保证。
false
(以使其与您的说明兼容)。假设您在多核计算机上运行。此外,假设线程A在Core 1中分配,而线程B在Core 2中分配。
线程A读取布尔值:它必须读取false
(参见上一个要点)。当读取发生时,可能发生某些内存页面(包括包含该布尔值的内存页面)将被缓存到Core 1的L1缓存或L2缓存中 - 任何本地缓存具体核心。
线程A否定并存储布尔值:它现在将存储true
。但问题是:在哪里?在发生之前 - 发生之前,线程A可以自由地将此新值存储在运行该线程的Core的本地缓存中。因此,该值可能会在Core 1的L1 / L2高速缓存上更新,但在处理器的L3高速缓存或RAM中将保持不变。
经过一段时间(根据您的挂钟),线程B读取布尔值:如果线程A没有将更改刷新到L3或RAM,线程B读取false
完全有可能。另一方面,如果线程A刷新了更改,则可能线程B将读取true
(但仍然无法保证 - 线程B可能已经收到了线程的副本M对存储器的看法,由于之前没有发生,它不会再次进入RAM并仍然会看到原始值。
保证任何事情的唯一方法是在之前发生 :它会强制线程A刷新其内存,并且会强制线程B不是从本地缓存中读取,而是真正从“权威”中读取它。源。
如果没有事先发生,正如您从上面的示例中看到的那样,任何事情都可能发生,无论在不同线程中的事件之间经过了多少时间(从您的角度来看)。
现在,一个重要问题:为什么volatile
会解决示例2中的问题?
如果该布尔变量标记为volatile
,并且根据上面的示例2(即从挂钟的角度来看)进行交错操作,那么,只有这样,线程B才能保证看到true
(即,根本没有任何保证)。
原因是volatile
有助于确定之前的关系。它如下:对volatile
变量的写入发生 - 在对同一变量的任何后续读取之前。
因此,通过标记变量volatile
,如果从时序角度看,线程B仅在线程A更新后才读取,则线程B保证看到更新(从内存一致性的角度来看)。
现在有一个非常有趣的事实:如果线程A对非易失性变量进行了更改,那么更新一个volatile变量,然后(从挂钟的角度来看)线程B读取该volatile变量,它也保证线程B将看到非易失性变量的所有更改!这是由非常复杂的代码使用,它们希望避免锁定并且仍然需要强大的内存一致性语义。它通常被称为易失性变量捎带。
作为最后的评论,如果你试图模拟(缺乏)发生在之前的关系,它可能会令人沮丧......当你把东西写到控制台时(即{{ 1}}),JVM可能会在多个不同的线程之间进行大量的同步,因此很多内存实际上可能会被刷新,并且你不一定能够看到你正在寻找的效果......它和#39;很难模拟这一切!