Java 如何使我的代码线程安全?
给定一个带有静态方法的Java 如何使我的代码线程安全?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,给定一个带有静态方法的Factory类为SomeModel类创建实例,它将在多线程环境中运行。此工厂有三种方法: 开始 停止 createSomeModel 以及状态字段,该字段位于: 关闭 开始 启动\u失败 开始 关闭 关闭\u失败 以下是工厂类的当前设计: public class Factory { enum State{ shutted, starting, starting_failed, started, shutting, shutting_failed
Factory
类为SomeModel
类创建实例,它将在多线程环境中运行。此工厂有三种方法:
开始
停止
createSomeModel
以及状态
字段,该字段位于:
关闭
开始
启动\u失败
开始
关闭
关闭\u失败
以下是工厂
类的当前设计:
public class Factory {
enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed
}
State state;
public static void start(){
// can only be invoked when state=shutted
}
public static void stop(){
// can only be invoked when state=started
}
public static void restart(){
stop();
start();
}
public static SomeModel create(){
// can only be invoked when state=started
}
}
我的要求是:create
方法只能在state==started
时调用,start
方法只能在state==shutted | | state==shutting失败
时调用,stop
方法只能在state==started | state==starting失败
时调用
public enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed;
}
public class Factory {
private State state;
public synchronized void start(){
if(state != State.shutted) {
throw new RuntimeException("Can only be invoked when state=shutted");
}
// do task
}
public synchronized void stop(){
if(state != State.started) {
throw new RuntimeException("Can only be invoked when state=started");
}
// do task
}
public synchronized void restart(){
stop();
start();
}
}
我知道这与线程同步问题有关,但我对自己的线程知识没有信心。请帮助我。此方法不会同步create方法,因此这不会成为瓶颈。当你停下来的时候,不要让新创建的执行。
双重检查“if state==started”是避免竞争条件所必需的
可能有比使用Thread.sleep for wait更好的解决方案,所有的创建模型都将完成,但我不知道如何轻松完成
希望这能帮助你
enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed
}
private Factory() {
// singleton: no more than 1 instances allowed
}
public static Factory getInstance() {
return instance;
}
private static final Factory instance = new Factory();
private final AtomicInteger threadsCreatingModel = new AtomicInteger();
private volatile State state;
public synchronized void start(){
if(state != State.shutted) {
throw new RuntimeException("Can only be invoked when state=shutted");
}
state = State.starting;
// TODO: task
}
public synchronized void stop() throws InterruptedException {
if(state != State.started) {
throw new RuntimeException("Can only be invoked when state=started");
}
state = State.shutting;
// wait all threads that are creating SomeModel
while (threadsCreatingModel.intValue() > 0) {
Thread.sleep(500);
}
// TODO: task
}
public SomeModel create(){
if(state == State.started) {
threadsCreatingModel.incrementAndGet();
if(state == State.started) {
// TODO: task
}
threadsCreatingModel.decrementAndGet();
}
}
我建议您根本不要使用静态方法
取而代之的是,创建工厂
类的对象,并让所有方法都同步
public enum State{
shutted, starting, starting_failed, started, shutting, shutting_failed;
}
public class Factory {
private State state;
public synchronized void start(){
if(state != State.shutted) {
throw new RuntimeException("Can only be invoked when state=shutted");
}
// do task
}
public synchronized void stop(){
if(state != State.started) {
throw new RuntimeException("Can only be invoked when state=started");
}
// do task
}
public synchronized void restart(){
stop();
start();
}
}
希望这有帮助。无需同步。对状态使用volatile或AtomicReference。
我给出了使用volatile的示例。最好与基元类型一起使用,因此必须为不同的状态添加int值。虽然您可以使用枚举的序数,但这种方式有点清楚。否则,您可以使用原子引用
public class Factory {
private static volatile int factoryState;
public synchronized void updateFactoryState(State newState, State ... expectedStates){
for (State state : expectedStates)
if(factoryState == State.shutted.getStateVal()){
factoryState = newState.getStateVal();
}
}
public void start(){
try{
updateFactoryState(State.starting, State.shutted, State.shutting_failed);
System.out.println("steps to start the factory");
//someExpensiveStartupMethod();
}catch (Exception e){
updateFactoryState(State.starting_failed, State.starting);
}
updateFactoryState(State.started, State.starting);
}
public void stop(){
try{
updateFactoryState(State.shutting, State.started, State.starting_failed);
System.out.println("steps to stop the factory");
//someExpensiveStopFactoryMethod();
}catch (Exception e){
updateFactoryState(State.shutting_failed, State.shutting);
}
updateFactoryState(State.shutted, State.shutting);
}
public void restart(){
stop();
start();
}
public static SomeModel create(){
if(factoryState == State.started.getStateVal()) {
System.out.println("Create Model");
} else{
throw new RuntimeException("Can not create Model.Factory not in started state.");
}
return null;
}
enum State{
shutted(0), starting(1), starting_failed(2), started(3), shutting(4), shutting_failed(5);
private final int stateVal;
State(int i) {
stateVal = i;
}
public int getStateVal() {
return stateVal;
}
}
class SomeModel {}
}
使用synchronized
块。您确定Factory
需要使用static
方法吗?看起来您希望在整个应用程序中都有一个Factory
的实例,并且客户端不需要调用start
方法。@LuiggiMendoza是的,您是对的,使用静态方法有那么糟糕吗?我应该使用单例模式吗?有static
方法并不坏,但是start
并不意味着是static
。您可以将您的工厂
设置为枚举,它将是一个单例,并且其初始化将是线程安全的。不过,您应该应用一些技术,使方法的执行是线程安全的。由于您没有提供有关方法的具体细节,我们只能声明您在验证工厂
的状态后,应使用同步
块来实现启动
和停止
方法,而create
方法根本不需要任何同步,除非它修改工厂的状态
。如果状态
仍然是无效状态,您将使用if
检查状态,然后抛出一个RuntimeException
,指出工厂
尚未初始化。此实现已中断,因为start()、stop()、create()包含争用条件。一般来说,volatile仅适用于以下情况:您希望读取共享值而不更改它,或者您希望以原子方式更改原语值,并且不必关心其当前数字。如果需要,请再次阅读volatile。最高级别的线程安全性来自不变性。读取不可变变量(如volatile或any)既不需要任何安全性,也不需要volatile提供对所有基元类型的原子操作。请再次访问volatile。代码中的问题:操作a)if(factoryState==…)
;操作b)factoryState=nextState
。如果线程在a)之后但在b)之前暂停,则factoryState可能会在线程继续工作之前收到意外值。这是一个竞争条件。同意竞争条件:),但仍然不同意声明的其他部分,并支持上述评论。但是“创建”方法如何?同步此方法将导致性能下降。但是“创建”方法如何?同步此方法将导致性能缺陷。我已更改代码,以便创建方法不需要同步,并且停止等待所有创建方法完成。