java编程和问题java单线程多线程(单线程与多线程)
我有一个使用单例模式的程序。我需要使用线程,并记住在使用线程机械化之前和之后,输出应该是相同的。我的意思是避免出现“断模式”的情况,即线程忽略单个对象,而创建更多的对象。但是,我失败了。我尝试使用“同步”,但没有任何改变。同样的错误结果 我的主菜是Runnablejava编程和问题java单线程多线程(单线程与多线程),java,multithreading,singleton,Java,Multithreading,Singleton,我有一个使用单例模式的程序。我需要使用线程,并记住在使用线程机械化之前和之后,输出应该是相同的。我的意思是避免出现“断模式”的情况,即线程忽略单个对象,而创建更多的对象。但是,我失败了。我尝试使用“同步”,但没有任何改变。同样的错误结果 我的主菜是Runnable public class Main implements Runnable { Main(){} public void run () { Counter[] cou
public class Main implements Runnable {
Main(){}
public void run ()
{
Counter[] counters = new Counter[5];
for(int i = 0; i < counters.length; i++)
{
counters[i] = Counter.getCounter();
}
for(int i = 0; i < counters.length; i++)
{
counters[i].increment();
System.out.println("counter[" + i + "] = " + counters[i]);
}
for(int i = 0; i < 5; i++) {
counters[i].decrement();
System.out.println("counter[" + i + "] = " + counters[i]);
}}
public static void main(String[] args)
{
Main m1=new Main();
Main m2=new Main();
Main m3=new Main();
new Thread(m1).start();
new Thread(m2).start();
new Thread(m3).start();
}
}
在Java中,双重检查锁定过去常常被破坏。我不知道新的内存模型是否修复了它 除了“我真的需要一个单身汉吗?”这个问题之外,单身汉给你买东西的懒惰实例究竟是什么 没什么 如果您的单例实例非常昂贵,并且您可能不使用它,那么这可能是合理的。但这里的情况都不是这样 因此,如果你必须这样写:
public class Counter
{
// Edited at the recommendation of Sean and "Effective Java"; see below
private static class InstanceHolder
{
private static final Counter INSTANCE = new Counter();
}
private Counter() {}
public static Counter getInstance() { return InstanceHolder.INSTANCE; }
// The rest of the implementation follows.
}
不要使用双重检查的单例模式,不管它是否损坏,这都不是现代的方式 Java中的singleton应该使用内部类或枚举实现(请参见第3项:使用私有构造函数或枚举类型强制singleton属性): a)内部类单例模式:
public class MySingleton{
private MySingleton(){}
private static class InstanceHolder{
private static final MySingleton INSTANCE = new MySingleton();
}
public static MySingleton getInstance(){
return InstanceHolder.INSTANCE;
}
}
b)枚举单例模式
public enum MySingleton{
INSTANCE;
public static MySingleton getInstance(){
return INSTANCE;
}
}
您必须同步整个方法
在静态块中初始化singleton而不检查任何内容是最有意义的,除非您有数千个典型的未使用的singleton类,否则它不会影响性能。不完全确定您想要实现什么,但有一些事情是错误的
不是线程安全的而不是原子操作。您要么需要同步这两种方法,要么使用原子递增/递减方法递增/递减
- 您正在读取与修改计数器不同的计数器值,因此另一个线程可能在更新和读取
之间更改为值。如果需要显示,我建议使用AtomicInteger并从递增/递减返回新值println
- 综上所述,您可能可以用静态AtomicInteger实例替换计数器
中的双重检查锁定可能已中断。我不确定在同步wrt到可见性之外,静态的行为是什么。为了安全起见,我会删除初始的空检查getCounter
- 您所需的输出不会来自此代码。每个线程(其中有3个线程)使用相同的计数器实例,5次,每次打印两次。按我的计数,这是30条输出语句
- 这些输出的顺序永远无法预测,因为线程竞争递增/递减(单个)计数器值,因此它可能以随机方式上下波动。另外,数字值的打印可能会出现混乱,因为线程也在竞争
- 在类上进行同步是一种不好的做法,尤其是在公共类上,因为其他代码可能会在该类上进行同步并干扰您的锁定。最好的方法是使用
私有静态最终对象锁=新对象()代码>并在上面同步
- 您不需要在return语句周围放置()命令
希望这能有所帮助!多线程代码是一项困难/危险的业务,因此请小心处理!如果你问了一个问题,说明你的目标,也许有人可以帮你提供一些提示和/或模型答案。你错过了
private static volatile Counter myInstance;
这应该可以解决问题,但不要这样做。如图所示,使用Holder模式或eager初始化。或者更好的方法是,使用而不是。在声明
实例时,您可能需要初始化变量。值得注意的是类是延迟加载的,因此,仅使用一个公共静态final
值或一个enum
加一个值可能同样好,而且更简单/更安全。我认为在新的内存模型中,它可以工作,但只适用于易失性变量。如果整个方法是同步的,应该不会有问题,但它仍然很难看。我投票支持肖恩的答案。“有效的Java”是正确的方法。@duffymo:他指的是成千上万个不同的类,它们都是单例的,这确实是可能的。我知道他的意思。可能的对向往的达菲莫:我很高兴我们在这一点上意见一致。我试图指出,除非情况极端,否则静态初始化不是问题。“成千上万的单身汉”是一个夸张的说法。java.util
应该有一个Lazy
类来进行懒惰的评估;这是经常需要的,人们不知道如何正确地做。“内部类单例”和“枚举单例”是黑客攻击,只适用于全局状态。Spring只是让您用xml编写同样的东西。出于某种原因,人们认为xml不是代码。“这对他们的老板很好。”本施密特谢谢。维基百科文章不幸被更改,删除了链接
private static volatile Counter myInstance;