为什么Java Vector被认为是遗留类,已过时或已弃用?
使用并发时它的使用是否有效?
如果我不想手动同步对象而只想使用线程安全的集合而不需要创建底层数组的新副本(如CopyOnWriteArrayList
那样),那么使用它是否合适Vector
?
Stack
是Vector
的子类,我应该用什么来代替呢?
答案 0 :(得分:623)
Vector
在每个单独的操作上同步。这几乎不是你想做的事。
通常,您希望同步整个序列的操作。同步单个操作的安全性较低(例如,如果迭代Vector
,则仍需要取出锁以避免其他任何人同时更改集合,这将导致{{1}在迭代线程中)但也慢一些(为什么一旦足够就重复取出锁?)
当然,即使你不需要,也会有锁定的开销。
基本上,在大多数情况下,这是一种非常有缺陷的同步方法。正如 Brian Henk先生所指出的,您可以使用Collections.synchronizedList
之类的调用来装饰集合 - ConcurrentModificationException
将“调整大小的数组”集合实现与“同步每个操作“bit是设计不佳的另一个例子;装饰方法可以更清晰地分离顾虑。
至于Vector
等价物 - 我会先看Stack
/ Deque
。
答案 1 :(得分:78)
Vector是1.0的一部分 - 原始实现有两个缺点:
<强> 1。命名:向量实际上只是可以作为数组访问的列表,因此它应该被称为ArrayList
(这是{1.2}}的Java 1.2集合替代。)
<强> 2。并发:所有Vector
,get()
方法都是set()
,因此您无法对同步进行细粒度控制。
synchronized
和ArrayList
之间没有太大区别,但您应该使用Vector
。
来自API文档。
从Java 2平台v1.2开始,这个 班级被改造以实施 列表界面,使其成为 Java Collections Framework。不像 新的集合实现, 矢量是同步的。
答案 2 :(得分:41)
除了已经陈述的关于使用Vector的答案之外,Vector还有一些围绕枚举和元素检索的方法,这些方法与List接口不同,开发人员(特别是那些在1.2之前学习Java的人)可以倾向于使用它们在代码中。尽管枚举速度更快,但它们不会检查集合是否在迭代期间被修改,这可能会导致问题,并且考虑到可能会选择Vector进行同步 - 通过多线程的话务员访问,这使得它成为一个特别有害的问题。使用这些方法还会将大量代码耦合到Vector,因此使用不同的List实现替换它并不容易。
答案 3 :(得分:14)
您可以使用java.util.Collection
上的synchronizedCollection/List方法从非线程安全集合中获取线程安全集合。
答案 4 :(得分:6)
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
Mat delaunay(const Mat& points, int imRows, int imCols)
/// Return the Delaunay triangulation, under the form of an adjacency matrix
/// points is a Nx2 mat containing the coordinates (x, y) of the points
{
Mat adj(points.rows, points.rows, CV_32S, Scalar(0));
/// Create subdiv and insert the points to it
Subdiv2D subdiv(Rect(0,0,imCols,imRows));
for(int p = 0; p < points.rows; p++)
{
float xp = points.at<float>(p, 0);
float yp = points.at<float>(p, 1);
Point2f fp(xp, yp);
subdiv.insert(fp);
}
/// Get the number of edges
vector<Vec4f> edgeList;
subdiv.getEdgeList(edgeList);
int nE = edgeList.size();
/// Check adjacency
for(int e = 1; e <= nE; e++)
{
int p = subdiv.edgeOrg(e); // Edge's origin
int q = subdiv.edgeDst(e); // Edge's destination
if(p < points.rows && q < points.rows)
adj.at<int>(p, q) = 1;
// else
// {
// cout<<p<<", "<<q<<endl;
// assert(p < points.rows && q < points.rows);
// }
}
return adj;
}
int main()
{
Mat points = Mat(100, 2, CV_32F);
randu(points, 0, 99);
int rows = 100, cols = 100;
Mat im(rows, cols, CV_8UC3, Scalar::all(0));
Mat adj = delaunay(points, rows, cols);
for(int i = 0; i < points.rows; i++)
{
int xi = points.at<float>(i,0);
int yi = points.at<float>(i,1);
/// Draw the edges
for(int j = i+1; j < points.rows; j++)
{
if(adj.at<int>(i,j) > 0)
{
int xj = points.at<float>(j,0);
int yj = points.at<float>(j,1);
line(im, Point(xi,yi), Point(xj,yj), Scalar(255,0,0), 1);
}
/// Draw the nodes
circle(im, Point(xi, yi), 1, Scalar(0,0,255), -1);
}
}
namedWindow("im", CV_WINDOW_NORMAL);
imshow("im",im);
waitKey();
return 0;
}
inherits the synchronization overhead of java.util.Stack
, which is usually not justified.
It inherits a lot more than that, though. The fact that java.util.Vector
is a mistake in object-oriented design. Purists will note that it also offers a lot of methods beyond the operations traditionally associated with a stack (namely: push, pop, peek, size). It's also possible to do java.util.Stack extends java.util.Vector
, search
, elementAt
, setElementAt
, and many other random-access operations. It's basically up to the user to refrain from using the non-stack operations of remove
.
For these performance and OOP design reasons, the JavaDoc for java.util.Stack
recommends ArrayDeque
as the natural replacement. (A deque is more than a stack, but at least it's restricted to manipulating the two ends, rather than offering random access to everything.)