記事ディレクトリ
ストーリーライン
私には良き友人の光順がいて、人生を体験するために学校の隣に店を構え、ミルクティーバーガーレストランをオープンしました。
新規出店の際は、まず、商工局に登録し、支部を作る。
彼が工商局に到着したとき、彼らは彼に親切なリマインダーを与えました:XXXはプライベートファイルにすぎません、他の人といじってはいけません、あなたは何が起こったかの責任を負います。
登録し、支部を作って、さらには店舗を開いた後、店長になり始めましたが、当初はいろいろなことがあり、アカウントの募集、購入、宣伝、計算をしなければなりませんでした...
しかし、彼はこれらのことを個人的に行うことができ、ショップを最初に支援することができます。
シングルトンモード
次に、このストーリーはシングルトンモードのアプリケーションシナリオによく合うので、私の友人はシングルトンモードについてあなたと話したいと考えています。
シングルトンパターンとは何ですか?
プロジェクトでは、いくつかのクラスは「家族計画」である必要があります。つまり、このクラスは1つのインスタンスのみを持つことができます。複数のインスタンスがある場合、データの不整合のリスクがあります。
私が店を開く場合、2人の所有者がいる場合は、本日は別の注文で、署名するように言った、そして彼は他の人に署名しないように言った;この従業員はアクティブではない、私は開くように言った、彼は開くことはできない...乱雑ではありませんか?
シングルトンモード:クラスにインスタンスが1つしかないことを確認し、それにアクセスするためのグローバルアクセスポイントを提供します。
偶然にも、このパターンにはシングルトンクラスと呼ばれるクラスが1つしかないため、クラス図は描画しません。
シングルトンモードのアプリケーションシナリオの例:データの問題が発生した場合、データベースが最初に負担となり、キャッシュは当然実行されません。
シングルトンコードの実装
//这里是.h文件
//老板类单例
class Single_Boss
{
public:
static Single_Boss *instence();//获取数据库单例
//重点在这个函数
void run();
private:
Single_Boss();
~Single_Boss();
char *errmsg;
static Single_Boss *Boss;//实例
};
//源文件
Single_Boss *Single_Boss::Boss= NULL;
Single_Boss::Single_Boss()
{
cout << "Big Boss" << endl; //debug
}
Single_Boss::~Single_Boss()
{
cout<<"Seeyou Boss"<<endl;
}
Single_Boss* Single_Boss::instence()
{
if(!Boss)
{
Boss= new Single_Boss();
}
return Boss;
}
void Single_Boss::run(){
cout<<"你好,欢迎光临XXX,请问需要点什么服务?"<<endl;
}
int main()
{
//Single_Boss *boss = new Single_Boss(); //不信的话大可以将这一行放出来,下面那行屏蔽掉试试
Single_Boss *boss= Single_Boss::instence(); //这是在类外使用单例
boss->run();
return 0;
}
ブースト部分
マルチスレッドでのシングルトンモード
以前は本物のデータベースが目の前にありましたが、残念ながら私はそれを大切にしていませんでした。プロジェクトが繰り返しクラッシュするまで、それを再起動できるとしたらロックを追加できるかどうかわかりませんでした。。。
先に進み、ロマンチックな人物を数え、現在を見てください。
次のコードをもう一度見てみましょう。
Single_Boss* Single_Boss::instence() //1
{
if(!Boss) //2
{
Boss= new Single_Boss(); //3
}
return Boss;
}
マルチスレッドの場合、2つのスレッドが同時に2に入ると、どうすればよいですか?これはかなり正常ではないですか?予防策は全くありませんが、これは誰かに頭を与える行為ではありませんか?
何もない!!
だから、それを変更してください:
Single_Boss* Single_Boss::instence() //1
{
lock(db_mutex); //假设这个锁我已经初始化过了
if(!Boss) //2
{
Boss= new Single_Boss(); //3
}
unlock(db_mutex); //上锁和解锁一定要同时写,就算忘记写中间步骤,也要先写解锁
return Boss;
}
よろしいですか?下記のコメント欄に「1」と呼ぶ洞察力のある豚を知っている友達はいますか?
このように記述した場合、データベースを使用する前にロック操作を行う必要がありますが、安全ではありますが、負荷が大幅に増加します。
だから、もう一度変更してください:
Single_Boss* Single_Boss::instence() //1
{
if(!Boss){
//一重锁定
lock(db_mutex);
if(!Boss) //二重锁定
{
Boss= new Single_Boss();
}
unlock(db_mutex); //上锁和解锁一定要同时写,就算忘记写中间步骤,也要先写解锁
}
return Boss;
}
これを見て、一部の友人は疑問に思うかもしれません:if判断と上のロック位置を単に変更することでそれを行うことはできないのですか?外側に別のレイヤーを追加する理由はありませんか?
まだ問題があり
ます。2つのスレッドがあり、ifの最初のレイヤーの防御を突破した場合、1つのスレッドは時間内にロックの外側にスタックしますが、ロックはシングルトンを作成する部分のみをロックします。ロックが取得されるとスレッドがロックを解放しても、別のスレッドはロックを取得してその「シングルトン」を作成することができません。このロックの意味は何ですか?
ロックの内側と外側のロックにif判断が追加されます。最初のスレッドがロックスペースに入り、シングルトンが作成されると、後続のスレッドは、ロックを取得してもシングルトン作成ステップを実行しません。
これは優れたシングルトンモードであり、シングルトンモードの「レイジーマンモード」です。
空腹の中国人
怠惰な男がいて、空腹の男もいます。
空腹の中国スタイルは何ですか?空腹の男性モデルの鍵:初期化はインスタンス化です
上記のコードを微調整します。
Single_Boss *Single_Boss::Boss= new Single_Boss();
Single_Boss* Single_Boss::instence()
{
//不需要进行实例化
//if(!Boss)
//{
// Boss= new Single_Boss();
//}
return Boss;
}
一般的に、空腹なスタイルのロードによって引き起こされる欠点は、インスタンスを使用したくないが、インスタンスは構築されていることです。遅延スタイルの使用と比較すると、構築によってメモリの浪費が発生しますが、その実装は非常に単純で、スレッドの安全性を確保するための人工的なロックはありません。
怠惰または空腹ですか?
どちらを選択するかは、個人の好みによって異なります。以下にいくつかの提案を示します。
懒汉:在访问量较小时,采用懒汉实现。这是以时间换空间。
饿汉:由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
シングルトンモードの利点と欠点
利点
- シングルトンモードのメモリにはオブジェクトが1つしかないため、特にオブジェクトを頻繁に作成および破棄する必要があり、作成または破棄中にパフォーマンスを最適化できない場合は、メモリコストが削減されます。シングルトンモードの利点は非常に明白です。
- シングルトンモードでは、メモリの複数の占有を回避できます。
- シングルトンモードでは、システムにグローバルアクセスポイントを設定して、リソースアクセスを最適化および共有できます。私はこのトリックをよく使用しますが、すべてのデータテーブルのマッピング処理を担当するフラグシングルトンクラスを作成するのは本当に便利なので、とても気に入っています。(理解するには、私を個人的に信頼することができます)
不利益
- シングルトンモードには、通常、インターフェイスがなく、拡張するのは困難です。拡張したい場合は、リファクタリングを検討してください。
- シングルトンモードはテストには適していません。並行環境では、シングルトンが完了していないとテストできません。
はい。
作成は簡単ではありませんが、簡単に収集するのは良い習慣です。