Здесь есть две проблемы: Безопасная публикация, а затем последующая безопасность потока для mutate (shuffle()
), за которой следует чтение (get(0)
).
Я не думаю, что ваш кодовый адрес является безопасной публикацией вообще. Для этого используйте volatile
или final
, а для volatile
сделайте назначение последним в ctor.
public class Generator {
private final List list = new ArrayList<>();
public Generator() {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
}
Или
public class Generator {
private volatile List list;
public Generator() {
List temp = = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
temp.add(i);
}
list = temp;
}
Теперь я думаю, что вы можете синхронизироваться с list
(или любым другим объектом), чтобы получить безопасность потока. Вы должны убедиться, что get
находится внутри синхронизированного блока. Обратите внимание, что в вашем коде есть ошибка, и на самом деле он не выдает уникальных чисел.
public Integer generate() {
synchronized( list ) {
Collections.shuffle(list);
return list.get(0);
}
}
Или
public synchronized Integer generate() {
Collections.shuffle(list);
return list.get(0);
}
См. Брайан Гетц Параллелизм Java на практике для получения дополнительной информации, особенно Безопасная публикация. SO также кратко обсуждает шаблон безопасной публикации .
Получение уникальных чисел - это просто логика, не связанная с безопасностью потоков. Сначала перемешайте только один раз в ctor, затем просто увеличьте счетчик, чтобы вернуть числа по порядку. Помните, что в вашем списке только 1000 номеров, поэтому вы можете вернуть не более 1000 уникальных номеров.
private int index;
public synchronized Integer generate() {
if( index >= 1000 ) throw IllegalArgumentError();
return list.get( index++ );
}
Ваш класс должен реализовать оператор == в Вашем ClassName
bool operator == ( const Class& rhs );
и затем можно использовать
list.remove( Bad )
Если разумно к Вашему классу иметь оператор == (не только для, удаляют) - чем список:: удалите хорошо для Вас решение. Если оператор == только для списка:: удалите, чем это лучше для использования remove_if.
В следующем списке в качестве примера:: удалите и перечислите:: remove_if продемонстрирован.
struct Class
{
int a_;
int b_;
Class( int a, int b ):
a_( a ),
b_( b )
{}
bool operator == (const Class &rhs)
{
return (rhs.a_ == a_ && rhs.b_ == b_);
}
void print()
{
std::cout << a_ << " " << b_ << std::endl;
}
};
bool isEqual( Class lhs, Class rhs )
{
return (rhs.a_ == lhs.a_ && rhs.b_ == lhs.b_);
}
struct IsEqual
{
IsEqual( const Class& value ):
value_( value )
{}
bool operator() (const Class &rhs)
{
return (rhs.a_ == value_.a_ && rhs.b_ == value_.b_);
}
Class value_;
};
int main()
{
std::list<Class> l;
l.push_back( Class( 1, 3 ) );
l.push_back( Class( 2, 5 ) );
l.push_back( Class( 3, 5 ) );
l.push_back( Class( 3, 8 ) );
Class bad( 2, 5 );
std::cout << "operator == " << std::endl;
l.remove( bad );
std::for_each( l.begin(), l.end(), std::mem_fun_ref( &Class::print ) );
std::cout << "binary function predicat" << std::endl;
l.push_back( Class( 2, 5 ) );
l.remove_if( std::bind2nd( std::ptr_fun(isEqual), bad ) );
std::for_each( l.begin(), l.end(), std::mem_fun_ref( &Class::print ) );
std::cout << "functor predicat" << std::endl;
l.push_back( Class( 2, 5 ) );
l.remove_if( IsEqual( bad ) );
std::for_each( l.begin(), l.end(), std::mem_fun_ref( &Class::print ) );
return 0;
}
Удалить все элементы согласно Предикату:
struct Pred
{
bool operator()(int i) const
{
return i == 42;
}
};
std::list<int> l = ...;
l.remove_if(Pred());
или удалить все элементы со значением 42:
std::list<int> l = ...;
l.remove(42);
или для списка CMyClass:
struct Pred
{
bool operator()(const CMyClass& item) const
{
return item.GetSomething() == 42 && item.GetSomethingElse() == 314159;
}
};
std::list<CMyClass> l = ...;
l.remove_if(Pred());
Можно просто выполнить итерации по элементам, выдержать сравнение и стереться, если условие соответствует, например:
for (std::list<string>::iterator i = mylist.begin(), e = mylist.end(); i != e; )
{
if (*i == "foobar")
i = mylist.erase(i);
else
++i;
}
Создайте класс, который принимает плохое значение и хранит его в членской переменной. Затем реализуйте
bool operator()(CMyClass const &currVal) {
return (currVal is equal to this->bad);
}
Передайте экземпляр этого объекта к remove_if
Оператор реализации == (константа CMyClass и).
например:
#include <list>
#include <iostream>
#include <iterator>
using namespace std;
class CMyClass {
public:
CMyClass(const int d) : data(d) {}
bool operator==(const CMyClass &rhs) { return data == rhs.data; }
friend
ostream& operator<<(ostream &ost, const CMyClass &rhs) { return ost << rhs.data; }
private:
int data;
};
int main(int, char **) {
list<CMyClass> li;
CMyClass a(1);
CMyClass b(8);
li.push_back(a);
li.push_back(b);
copy(li.begin(), li.end(), ostream_iterator<CMyClass>(cout,"\n"));
li.remove(a);
copy(li.begin(), li.end(), ostream_iterator<CMyClass>(cout,"\n"));
return 0;
}
Результат:
1 8 8
using namespace std;
class Foo
{
public:
Foo(int newVal){value = newVal;}
int value;
};
class checkEqual : public binary_function<Foo, Foo, bool>
{
public:
bool operator()(const Foo &inputOne, const Foo &inputTwo) const
{ return inputOne.value == inputTwo.value;}
// implement your comparison here
};
int main(int count, char** args)
{
list<Foo> myList;
for(int x = 0; x < 10; ++x)
myList.push_back(Foo(x));
Foo bad(5);
myList.remove_if(bind2nd(checkEqual(), bad));
return 0;
}
Или если Вы хотите перегрузиться ==, можно сделать:
class Foo
{
public:
Foo(int newVal){value = newVal;}
int value;
bool operator==(const Foo &other) const
{ return this->value == other.value;}
// your comparison here
};
И затем:
myList.remove(bad);