在以下代码中,
public class Mainly {
private Map<Integer, String> map = new HashMap<Integer, String>();
private volatile int index = 0;
public void set(Integer key, String value) {
map.put(key, value); // (1)
index ++; // (2)
}
public String get(Integer key) {
int i = index; // (3)
return map.get(key); // (4)
}
}
如果(1)
发生在(4)
之前,是否意味着get
方法始终会读取最新值?
答案 0 :(得分:2)
好问题, 在单线程应用程序中,您将无法识别volatile变量的工作,现在让我们看看它是如何工作的。
Java volatile关键字用于将Java变量标记为&#34;存储在主存储器中#34;。更准确地说,这意味着,每次读取一个易失性变量都将从计算机的主存储器读取,而不是从CPU缓存读取,并且每次写入一个易失性变量都将被写入主存储器,而不仅仅是到CPU缓存。
想象一下两个或多个线程可以访问共享对象的情况,该共享对象包含一个声明如下的计数器变量:
public class SharedObject {
public int counter = 0;
}
想象一下,只有线程1递增计数器变量,但线程1和线程2都可能不时读取计数器变量。
如果计数器变量未声明为volatile,则无法保证何时将计数器变量的值从CPU缓存写回主存储器。这意味着CPU缓存中的计数器变量值可能与主存储器中的计数器变量值不同。
线程没有看到变量的最新值的问题,因为它还没有被另一个线程写回主内存,被称为&#34; visibility&#34;问题。其他线程看不到一个线程的更新。
通过声明计数器变量volatile,对计数器变量的所有写操作都将立即写回主存储器。此外,计数器变量的所有读取都将直接从主存储器中读取。以下是计数器变量的volatile声明的外观:
public class SharedObject {
public volatile int counter = 0;
}
声明变量volatile因此保证了对该变量的其他写入线程的可见性。
此处提供有关volatile关键字的更详细说明: http://tutorials.jenkov.com/java-concurrency/volatile.html
如果您对挥发性产品仍存在一些困惑,请告诉我。
如果得到我的观点,请点击核查符号接受答案。
快乐的编码!!民间
答案 1 :(得分:2)
您似乎正在努力使您的读/写操作线程安全。
你这样做的方式是错误的,首先关闭的是你的Mainly类用作单身人士吗?
如果是,则应同步<!DOCTYPE html>
<html>
<head>
<script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<style>
.canvasBackground {
background-color: white
}
.table {
border-collapse: collapse;
border: #d0d4d5 solid 1px;
border-spacing: 0px;
font: normal 11px Georgia, 'Times New Roman', Times, serif;
letter-spacing: 1px;
line-height: 14px;
padding: 5px;
width: 100%
}
.headerStyle {
vertical-align: middle;
}
.headerRowStyle {
background-color: #fff;
border-bottom: 3px solid #ccc;
color: #4078a9;
font-size: 14px;
height: 48px;
line-height: 14px;
padding: 10px 5px 5px 5px
}
.headerCellStyle {
border-left: 1px solid #d0d4d5;
}
.tableBodyStyle {
text-align: left;
vertical-align: middle
}
.tableRowStyle {
background-color: #fff;
border-bottom: 1px solid #d0d4d5;
color: #565656;
padding: 5px 5px
}
.tableCellStyle {
border: 1px solid #d0d4d5;
}
</style>
</head>
<body>
<div class="canvasBackground">
<div class="tables"></div>
</div>
<script>
function evalColor(d) {
if (d == "Green" | d == "Yellow" | d == "Red") {
return createSVG(d);
}
if (d != "Green" | d != "Yellow" | d != "Red") {
return d;
}
}
function evalText(d) {
if (d == "Green" | d == "Yellow" | d == "Red") {
console.log(d);
} else if (d != "Green" | d != "Yellow" | d != "Red") {
return d;
}
}
function createTable() {
var dataSet = [{
"Title": "Title 1",
"ID": "00001",
"Name": "Rena",
"Color 1": "Yellow",
"Color 2": "Green"
}, {
"Title": "Title 2",
"ID": "00002",
"Name": "Elsa",
"Color 1": "Green",
"Color 2": "Red"
}, ];
var div = d3.select('.tables');
// append a table to the div
var table = div.append("table")
.attr({
id: "sample",
class: 'table'
})
.classed("display", true);
// append a header to the table
var thead = table.append("thead")
.attr({
class: 'headerStyle'
});
// append a body to the table
var tbody = table.append("tbody")
.attr({
class: 'tableBodyStyle'
});
// append a row to the header
var theadRow = thead.append("tr")
.attr({
class: 'headerRowStyle'
});
// return a selection of cell elements in the header row
// attribute (join) data to the selection
// update (enter) the selection with nodes that have data
// append the cell elements to the header row
// return the text string for each item in the data array
theadRow.selectAll("th")
.data(d3.keys(dataSet[0]))
.enter()
.append("th")
.text(function(d) {
return d;
});
// table body rows
var tableBodyRows = tbody.selectAll("tr")
.data(dataSet)
.enter()
.append("tr")
.attr({
class: 'tableRowStyle'
});
//table body row cells
tableBodyRows.selectAll("td")
.data(function(d) {
return d3.values(d);
})
.enter()
.append("td")
.text(function(d) {
return evalText(d);
})
.filter(function(d){
return (d === "Green" ||
d === "Yellow" ||
d === "Red");
})
.append(function(d) {
return createSVG(d);
});
}
function createSVG(d) {
function colorPicker(value) {
if (value == "Green") {
return "#7aa25c";
} else if (value == "Yellow") {
return "#f4f85e";
} else if (value == "Red") {
return "#d84b2a";
}
}
function colorFill(value) {
if (value == "Green") {
return "#fff";
} else if (value == "Yellow") {
return "#565656";
} else if (value == "Red") {
return "#fff";
}
}
function letterChoice(value) {
if (value == "Green") {
return "G";
} else if (value == "Yellow") {
return "Y";
} else if (value == "Red") {
return "R";
}
}
var w = 50;
var h = 50;
var kpi = document.createElement("div");
var svg = d3.select(kpi).append("svg")
.attr({
width: w,
height: h
});
var elem = svg.selectAll("div")
.data([d]);
var elemEnter = elem.enter()
.append("g");
elemEnter.append("circle")
.attr({
cx: 28,
cy: 25,
r: 20
})
.style("fill", colorPicker);
elemEnter.append("text")
.style("fill", colorFill)
.attr("dy", 30)
.attr("dx", 25)
.text(letterChoice);
return kpi;
}
createTable();
</script>
</body>
</html>
和set
方法,例如:
get
这样,如果您的字段被正确封装,则所有线程将同时看到public synchronized void set(Integer key, String value) {
map.put(key, value);
index ++;
}
public synchronized String get(Integer key) {
int i = index;
return map.get(key);
}
和map
的相同值。
这里不需要使用index
关键字,因为前缀/后缀增量/减量在Java中不是原子的。在您的情况下,仅仅确保同步是不够的。
答案 2 :(得分:0)
我有一个全局Map,只有一个线程更新它,并且有几个线程读取 map中的值。我能以这种方式读取地图中的最新值吗?
ConcurrentHashMap可能正是您要找的。来自API:
检索反映了最近完成的更新的结果 在他们开始时坚持的行动。
但是仍然无法保证在读取之前启动的更新将完成。您的返回可能有点陈旧,但至少它将保证是最新的有效值,而不是一些被修复的过程中被修改的状态。
在回答原始问题时,不,在索引变量上使用volatile对此没有帮助。其他人已经对此作出了很好的解释。两个主要选项是对读取和写入使用线程限制,或使用同步。