python 单例模式还是多New几个,区别在哪儿,性能还是需求

博客分类:
面试被问到一个线程安全的单例模式问题,想拿出来讨论一下,我通常会使用的这样的写法来实现单例:
public class Singleton {
private Singleton() {}
private static Singleton instance =
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
单例的目的是为了保证运行时Singleton类只有唯一的一个实例,最常用的地方比如拿到数据库的连接,Spring的中创建BeanFactory这些开销比较大的操作,而这些操作都是调用他们的方法来执行某个特定的动作。
面试官的问题是:单例会带来什么问题?
我第一反映就是如果多个线程同时调用这个实例,会有线程安全的问题,当时就这么说了,然后他问:“怎么实现一个线程安全的单例模式呢?”
这个问题我没有回答上来,当时脑子里闪了一下如果用synchronized来锁定可能会有一些问题,至于是什么问题没有想明白,就选择没有回答。
这里请问各位高手,
1、如果不执行修改对象的操作的情况下,单单执行一个读取操作,还有没有进行同步的必要?
2、保证单例的线程安全使用synchronized会产生什么样的问题?
3、不使用synchronized,有什么方式来保证线程安全?
4、假如下次再面试遇到这种情形,用什么方式回答会使面试官感到比较满意?
--------------------------------------------------------------------------------------------------------------------------------------------------------------
感谢大家的讨论与支持,总结一下:
实际上使用什么样的单例实现取决于不同的生产环境,懒汉式也就是我在上面举得那个例子,这种方式适合于单线程程序,多线程情况下需要保护getInstance()方法,否则可能会产生多个Singleton对象的实例。
在此基础上确保getInstance()方法一次只能被一个线程调用就需要在getInstance()方法之前加上 synchronized 关键字,锁定整个方法,
public class Singleton{
private static Singleton instance=
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
但很多时候我们通常会认为锁定整个方法的是比较耗费资源的,代码中实际会产生多线程访问问题的只有 instance = new Singleton(); 这一句,
为了降低 synchronized 块性能方面的影响,只锁定instance = new Singleton(); 这一句,“weishuang”回帖中使用的就是这种方式:
public class Singleton{
private static Singleton instance=
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
instance=new Singleton();
分析这种实现方式,两个线程可以并发地进入第一次判断instance是否为空的if 语句内部,第一个线程执行new操作,第二个线程阻断,当第一个线程执行完毕之后,第二个线程没有进行判断就直接进行new操作,所以这样做也并不是安全的。
为了避免第二次进入synchronized块没有进行非空判断的情况发生,添加第二次条件判断,就像“tomorrow009”在帖子中回复的示例一样
public static Singleton getInstance(){
if(instance == null){
synchronize{
if(instance == null){
instance =
new Singleton();
这样就产生了二次检查,但是二次检查自身会存在比较隐蔽的问题,查了在DeveloperWorks上的一篇文章,对二次检查的解释非常的详细:
其实找到这篇文章之后,我的问题基本上就已经可以解决了,但是看到回帖的同学们也有一些和我一样的问题,还想把这个问题继续梳理一遍。
使用二次检查的方法也不是完全安全的,原因是 java 平台内存模型中允许所谓的“无序写入”会导致二次检查失败,所以使用二次检查的想法也行不通了。
在最后提出这样的观点:“无论以何种形式,都不应使用双重检查锁定,因为您不能保证它在任何 JVM 实现上都能顺利运行。”
"netrice"在回复中提到了使用“java5以后的volatile关键字”,用volatile关键字来声明变量,声明成 volatile 的变量被认为是顺序一致的,即,不是重新排序的。但是volatile关键字的特性并不适用于这篇帖子所讨论的问题关键。
通过上面的分析,可以看到使用懒汉式的lazy方式实现单例弯弯绕太多,在单线程编程的情况下懒汉式单例实现是没有任何问题的,如果在多线程的情况下,我们需要比较小心,对getInstances()方法加上synchronized关键字,这样虽然可能有一些性能上的牺牲,但是更加的安全。绕了这么大的一个弯,又回来了:
/* 安全的方式 1 */
public class Singleton{
private static Singleton instance=
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance==null){
instance=new Singleton();
提到的另外一种实现方式是这样的,放弃使用 synchronized 关键字,而使用 static 关键字:
/* 安全的方式 2 */
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
这种方式没有使用同步,并且确保了调用static getInstance()方法时才创建Singleton的引用(static 的成员变量在一个类中只有一份)。
还有“keshin”提到的方式则更加灵巧,没有使用同步但保证了只有一个实例,还同时具有了Lazy的特性(出自)
/* 安全的方式 3 */
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
public static Resource getResource() {
return ResourceFactory.ResourceHolder.
static class Resource {
上面的方式是值得借鉴的,在ResourceFactory中加入了一个私有静态内部类ResourceHolder ,对外提供的接口是 getResource()方法,也就是只有在ResourceFactory .getResource()的时候,Resource对象才会被创建,
这种写法的巧妙之处在于ResourceFactory 在使用的时候ResourceHolder 会被初始化,但是ResourceHolder 里面的resource并没有被创建,
这里隐含了一个是static关键字的用法,使用static关键字修饰的变量只有在第一次使用的时候才会被初始化,而且一个类里面static的成员变量只会有一份,这样就保证了无论多少个线程同时访问,所拿到的Resource对象都是同一个。
饿汉式的实现方式虽然貌似开销比较大,但是不会出现线程安全的问题,也是解决线程安全的单例实现的有效方式。
至于ThreadLocal,我认为还是应该由使用场景来决定。
在《Java与模式》中,作者提出:“饿汉式单例类可以在Java语言实现,但不易在C++内实现,因为静态初始化在C++里没有固定的顺序,因而静态的instance变量的初始化与类的加载顺序没有保证,可能会出问题。这就是为什么GoF在提出单例类的概念时,举的例子是懒汉式的。他们的书影响之大,以致Java语言中单例类的例子也大多是懒汉式的。实际上,本书认为饿汉式单例类更符合Java语言本身的特点。”
由此可见在应用设计模式的同时,分析具体的使用场景来选择合适的实现方式是非常必要的。
寻找问题解决过程中找的一些参考资料:
因为在精华帖中没有找到很流畅解释这个问题的内容才发了这个帖子,还是很不幸的被评为了新手帖,但如果下次有面试官问有关线程安全的单例模式问题,我想我知道该怎么回答了。
论坛回复 /
(45 / 32166)
viei 写道我一般这样写
public class Singleton{
static class SingletonHolder{
& static Singleton instance=new Singleton();
public static Singleton getInstance(){
& return Singleton.instance();
最早从google的一个叫lee的人那里学来的,现在基本都这样写
恩,这样写确实精妙,避免了对静态数据域直接赋值所带来的浪费。不用在不用的时候创建对象。
呵呵,我自己说的拗口了。
Singleton.instance();
的instance()方法哪里定义的?》》》》》》》》》》》》》》》
我一般这样写
public class Singleton{
static class SingletonHolder{
& static Singleton instance=new Singleton();
public static Singleton getInstance(){
& return Singleton.instance();
最早从google的一个叫lee的人那里学来的,现在基本都这样写
恩,这样写确实精妙,避免了对静态数据域直接赋值所带来的浪费。不用在不用的时候创建对象。
呵呵,我自己说的拗口了。
xl10230 写道tomorrow009 写道Singleton模式分两种,“懒汉”和“恶汉” 恶汉模式也就是前面很多人提到的
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){
//私有化构造函数.
public static Singleton getInstance(){
由于实例在类加载时就已经创建,所以不存在线程同步问题,如果该Singleton初始化时不需要很大的开销(比如io操作/数据库连接)之类的,通常用这种办法就可以了.
某些情况下我们希望实例只有被第一次用到的时候才创建,那么这时候就使用“懒汉”模式,初学者通常会采用LZ的写法,正如面试官所说,这样会有线程同步问题,而导致多个实例被创建。如果在 getInstance()方法前面加上synchronize,又会大大降低系统性能。其实我们需要考虑的是,究竟要同步哪里? 我们只需要同步new Singleton()这个部分,保证只有一个实例被创建出来即可,而无须同步整个getInstance()方法,那么就可以考虑这样做
public static Singleton getInstance(){
if(instance == null){
synchronize{
if(instance == null){
instance =
new Singleton();
& 应该就是这样了。
顶一个double checked模式
真搞不懂,这样跟
&&& public static Singleton getInstance(){
&&&&&&&&&&& synchronize{
&&&&&&&&&&&&&& if(instance == null){
&&&&&&&&&&&&&&&&& instance =& new Singleton();
&&&&&&&&&&&&&& }
&&&&&&&&&&&&&
&&&&&&&&&&& }
&&& }
有什么区别,多此一举吗?
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
public static Resource getResource() {
return ResourceFactory.ResourceHolder.
static class Resource {
java concurrency in practice中建议的方式
又学习了单例模式一种新的写法
通常有两种常见的策略实现单例,一如lz所言,即所谓lazy形式的。如果害怕线程安全问题,而又不想用synchronized影响性能的话,不如用另一种:
public class Singleton {&
&&& private Singleton() {}&
&&& // 载入class时立即初始化
&&& private static Singleton instance = new Singleton();&
&&& public static Singleton getInstance() {&
当然这种也有缺点,instance会立即初始化,而不管是否实际用到。:)
这个缺点根本就不是缺点。你用不到这个类为什么访问它呢,访问它获得实例必须初始化。说白了这个所谓缺点仔细想明白,你会发现这是最佳实现方式。
bencode 写道keshin 写道
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
public static Resource getResource() {
return ResourceFactory.ResourceHolder.
static class Resource {
java concurrency in practice中建议的方式
这个好, 延迟初始化,线程安全,效率高(没有使用同步锁,而由类加载器保证) 简洁
凤舞凰杨都跟你们说了多看看书,还是有人搞出什么double check啊之类的来.
上面这个是目前最简单有效的单例方式.
就是一堆人视而不见
我也看过developerworks上讨论的double-check的问题。但据说那个问题在jdk1.5已经解决了。http://zhangle.iteye.com/blog/259991
应该可以像http://www.ibm.com/developerworks/cn/java/j-dcl.html中所说的那样分析出来的,但我电脑上目前没安装Visual Studio,先留言在这,回去试出来了再说。
……楼上已经说了。
bencode 写道keshin 写道
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
public static Resource getResource() {
return ResourceFactory.ResourceHolder.
static class Resource {
java concurrency in practice中建议的方式
这个好, 延迟初始化,线程安全,效率高(没有使用同步锁,而由类加载器保证) 简洁
凤舞凰杨都跟你们说了多看看书,还是有人搞出什么double check啊之类的来.
上面这个是目前最简单有效的单例方式.
就是一堆人视而不见
是的上面是最简单有效的 Lazy Loading Singletons实现方法,关于几种Singleton实现方法,Google工程师Bob Lee有个很好的帖子 http://crazybob.org/2007/01/lazy-loading-singletons.html。
总结成以下三点:
1. 使用Synchronized同步getInstance方法, 简单有效适合所有的JVM版本,但Lock contention带来性能开销
2. 使用Double-checked Locking 和只同步create instance的部分,同时必须声明单列变量为volatile,否则同样不是完全线程安全的。同样由于Java Memory Model的对volatile的模糊定义,这个模式无法使用在5之前的JVM。新的JMM对volatile定义更明确,compound operation (比如++, get-set)也是原子性的,所以DCL可以放心使用在Java 5中。使用在5以后版本,可以提升10%性能(bob lee测试)
3. 最快的方法还是Lazy Loading Singletongs, 它从Initialization on Demand Holder (IODH) 模式演化而来, 针对这个模式Effective Java 第48条也有很详细的描述。
最后还是要看情况来合理使用各种技巧, 很多时候其实最老土的发法一还是很好很管用的
tomorrow009 写道Singleton模式分两种,“懒汉”和“恶汉” 恶汉模式也就是前面很多人提到的
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){
//私有化构造函数.
public static Singleton getInstance(){
由于实例在类加载时就已经创建,所以不存在线程同步问题,如果该Singleton初始化时不需要很大的开销(比如io操作/数据库连接)之类的,通常用这种办法就可以了.
某些情况下我们希望实例只有被第一次用到的时候才创建,那么这时候就使用“懒汉”模式
第一种方式(加载时创建实例)有什么问题?类的加载机制是第一次调用static方法时类才加载,也就是在调用getInstance()方法时Singleton才被加载,这样跟第二种的加载时间有什么不同?不都是第一次使用时才加载吗?
以上是我的困惑,希望楼下有人给我解惑
同问。
只在调用静态方法getInstance时,instance 才会初始化。至少在JDK1.6是如此的。又何必去再里面定义一个内部类,加一个静态变量,在getInstance方法里面调用此变量呢。很疑惑。
PS 越看越觉得书读的少啊。。。
Hibernate的文档时看到了关于使ThreadLocal管理多线程访问的部分。具体代码如下
1.& public static final ThreadLocal session = new ThreadLocal();
2.& public static Session currentSession() {
3.&&&&& Session s = (Session)session.get();
4.&&&&& //open a new session,if this session has none
5.&& if(s == null){
6.&&&&& s = sessionFactory.openSession();
7.&&&&& session.set(s);
8.&& }
&&&&&
9. }
我们逐行分析
1。 初始化一个ThreadLocal对象,ThreadLocal有三个成员方法 get()、set()、initialvalue()。
&&& 如果不初始化initialvalue,则initialvalue返回null。
3。session的get根据当前线程返回其对应的线程内部变量,也就是我们需要的net.sf.hibernate.Session(相当于对应每个数据库连接).多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s(数据库连接)。
5。如果是该线程初次访问,自然,s(数据库连接)会是null,接着创建一个Session,具体就是行6。
6。创建一个数据库连接实例 s
7。保存该数据库连接s到ThreadLocal中。
8。如果当前线程已经访问过数据库了,则从session中get()就可以获取该线程上次获取过的连接实例。
LZ这个也没谈到Hibernate 你们干嘛要说Hibernate中的ThreadLocal啊 - - 崩溃啊啊!!!!!
就是一个管理Sessin的类
keshin 写道
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
public static Resource getResource() {
return ResourceFactory.ResourceHolder.
static class Resource {
java concurrency in practice中建议的方式
这个好, 延迟初始化,线程安全,效率高(没有使用同步锁,而由类加载器保证) 简洁
凤舞凰杨都跟你们说了多看看书,还是有人搞出什么double check啊之类的来.
上面这个是目前最简单有效的单例方式.
就是一堆人视而不见
tomorrow009 写道Singleton模式分两种,“懒汉”和“恶汉” 恶汉模式也就是前面很多人提到的
public class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){
//私有化构造函数.
public static Singleton getInstance(){
由于实例在类加载时就已经创建,所以不存在线程同步问题,如果该Singleton初始化时不需要很大的开销(比如io操作/数据库连接)之类的,通常用这种办法就可以了.
某些情况下我们希望实例只有被第一次用到的时候才创建,那么这时候就使用“懒汉”模式,初学者通常会采用LZ的写法,正如面试官所说,这样会有线程同步问题,而导致多个实例被创建。如果在 getInstance()方法前面加上synchronize,又会大大降低系统性能。其实我们需要考虑的是,究竟要同步哪里? 我们只需要同步new Singleton()这个部分,保证只有一个实例被创建出来即可,而无须同步整个getInstance()方法,那么就可以考虑这样做
public static Singleton getInstance(){
if(instance == null){
synchronize{
if(instance == null){
instance =
new Singleton();
& 应该就是这样了。
顶一个double checked模式
& 上一页 1
xiaozhi7616
浏览: 146188 次
来自: 北京
very good,
jiht594 写道楼主你好:这个第一段js代码+那一行htm ...
楼主你好:这个第一段js代码+那一行html代码我试的时候为什 ...
多谢 还有别的方法 例如取消linksbuilder 不 ...
嗯,写的不错,明白啥意思了。。。。。。就是和配置助手里面配的那 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'势不可去尽,话不可说尽,福不可享受尽,规矩不可行尽,凡事太尽,缘分必然早尽。想拥有未曾得到的,想得到的却未曾拥有,那是因为你没有做你从未曾做过的事。...
Java单例和多例的性能
公用类ThreadUtils,用于父线程等待子线程运行结束。
import java.util.L
public class ThreadUtils {
public static synchronized void regist(Runnable runnable, List&Runnable& runnableList){
synchronized (runnableList) {
runnableList.add(runnable);
public static synchronized void unregist(Runnable runnable, List&Runnable& runnableList){
synchronized (runnableList) {
runnableList.remove(runnable);
public static synchronized boolean hasThreadRunning(List&Runnable& runnableList){
synchronized (runnableList) {
return runnableList.size() & 0;
public static synchronized int getRunnningSize(List&Runnable& runnableList){
synchronized (runnableList) {
return runnableList.size();
常规的例子
public static void main(String[] args) throws InterruptedException {
Long start = System.currentTimeMillis();
List&Runnable& list = new ArrayList&Runnable&();
for(int i = 0; i & 10; i++){
new Thread(new Runnable() {
public void run() {
ThreadUtils.regist(this, list);
for(int j = 0; j & 1000; j++){
domestring();
ThreadUtils.unregist(this, list);
}).start();
while(ThreadUtils.hasThreadRunning(list)){
Thread.sleep(1);
System.out.println(System.currentTimeMillis() - start);
public static void domestring(){
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
例子中开了10个线程,每个线程做1000次domestring()方法,domestring()仅有一个动作,就是休眠1ms。
看一下运行情况,父线程等待子线程运行结束,多次运行的结果平均时间是:1005ms。
下面修改一下domestring()方法,在前面加上synchronized关键字,代码如下:
public synchronized static void domestring(){
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
然后再运行一下mian方法,父线程等待子线程运行结束,多次运行的结果平均时间是:10095ms。
可以看到,当domestring()加上synchronized关键字的时候比没有synchronized关键字足足慢了10倍。
从上面这两个例子,可能有人理解成java内部的实现原理是使用了ThreadLocal,将domestring()方法拷贝了一个副本给到各个线程。如果是这样,那么加上synchronized关键字,父线程等待子线程运行结束的时间应该等于没有synchronized关键字的运行时间。或许这样的理解并不正确。
假如理解成java的方法是支持并行调用的,一个线程在调用没有synchronized关键字的方法的时候,并不会等待方法是否执行结束,另外一根线程就可以同时调用相同的方法并且执行。而加上了synchronized关键字的时候,方法被锁,因此其他线程调用方法的时候,需要等待上一个线程的domestring()执行借宿。个人觉得这样的理解应该更贴切。
当domestring()在修改一个全局变量的时候,没有加synchronized关键字,是线程不安全的。
BizService .java
public class BizService {
static BizService bizService = null;
static synchronized BizService getInstance(){
if (instance == null) {
instance = new BizService ();
public void doSomething(){
Thread.sleep(1);
} catch (Exception e) {
public static void main(String[] args) throws InterruptedException {
Long start = System.currentTimeMillis();
List&Runnable& list = new ArrayList&Runnable&();
for(int i = 0; i & 10; i++){
new Thread(new Runnable() {
public void run() {
ThreadUtils.regist(this, list);
for(int j = 0; j & 1000; j++){
BizService.getInstance().doSomething();
ThreadUtils.unregist(this, list);
}).start();
while(ThreadUtils.hasThreadRunning(list)){
Thread.sleep(1);
System.out.println(System.currentTimeMillis() - start);
单例例子中开了10个线程,每个线程做1000次BizService.getInstance().domestring()方法,domestring()仅有一个动作,就是休眠1ms。父线程等待子线程运行结束,多次运行的结果平均时间: 1010ms。
这个例子和常规例子比较说明,单例类中的方法和和常规的静态方法,在性能上没有任何区别。单例仅仅是避免了多次重复创建对象,避免了内存的开销和减少gc的的活动。在一定情况下,完全可以使用静态方法去替换单例模式。
这里,我就不在测试单例方法(即BizService类的domestring())加上synchronized关键字的运行情况了,因为他实际上等同于静态方法加上了synchronized关键字。
同理,当domestring()在修改一个全局变量的时候,没有加synchronized关键字,是线程不安全的。
public static void main(String[] args) throws InterruptedException {
Long start = System.currentTimeMillis();
List&Runnable& list = new ArrayList&Runnable&();
for(int i = 0; i & 10; i++){
new Thread(new Runnable() {
public void run() {
ThreadUtils.regist(this, list);
BizService bizService = new BizService();
for(int j = 0; j & 1000; j++){
bizService.doSomething();
ThreadUtils.unregist(this, list);
}).start();
while(ThreadUtils.hasThreadRunning(list)){
Thread.sleep(1);
System.out.println(System.currentTimeMillis() - start);
多例例子中开了10个线程,每个线程做1000次BizService的domestring()方法,domestring()仅有一个动作,就是休眠1ms。父线程等待子线程运行结束,多次运行的结果平均时间: 1010ms。
在这个例子中几乎与单例没有多大的性能区别。因为在这个例子中:它没有产生大量的内存垃圾和gc活动。当它产生大量的内存垃圾和gc活动是,性能肯定有所下降。
单例和多例的注意事项
单例和多例的性能对比,孰优孰劣,不在纠结了。只要在开发中遵循下面的原则,一定能写出比较优美的代码。
使用单例:密切注意方法是否会出现线程不安全的情况。需要加上synchronized关键字的方法,一定不要漏了。
使用多例:在多线程中,注意尽量避免重复多次的创建对象和产生GC活动。
没有更多推荐了,10:52 提问
数据库连接单例和连接池效率区别在哪?
数据库连接问题。new一个数据库的连接对象是耗时耗资源的,因此不可能对每个请求都做一遍连接创建和关闭的操作,网上给的方法一般采用连接池。我的疑问就是,我如果采用单例模式,
这样的话,如果是多个线程请求数据库操作,那么直接调用静态getInstance方法(对此方法加锁),取得同一个数据库连接对象进行数据库操作,是不是可行的。我的理解是Connection在第一次实例化时,已经确定了它要连接时那个数据库,以后的操作也不会改变这些属性,因此不存在线程安全问题,而针对数据库本身的操作,数据应该也会提供一套同步机制,避免“脏数据”。这样的话,单例模式和池化相比,采用哪种方式更好?
按赞数排序
如果你是小型应用,保证不会有多线程同时使用这一条连接,那没问题;
多线程用同一条链接肯定是会出问题的,这个你可以自己写代码测试。
连接池的目的是为了减少反复的创建和关闭连接,同时又在一定程度上满足多线程可以分别用多条连接。
建议思考一下servlet采用的单实例多线程机制,单例模式与连接池似乎并不矛盾
数据库应该也会提供一套同步机智(why ? ) 。。事务如何保证?????????? ?
这是两个不同的概念
数据库连接单例是指在你项目运行期间,始终只有一个数据库连接。即这个链接在程序中是复用的
而连接池维持了到数据库服务器的多个物理连接,每当有新的数据库连接请求时,优先使用已存在的空闲的物理连接
显然前者是针对一个项目内部的
而后者是针对多个项目的(当然也适用项目内的多个独立连接)
其实在你频繁使用连接单例时,程序会自动为你建立连接痴,效率的区别在于你对sql的操作频率!
减少连接和销毁时间的消耗
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐}

我要回帖

更多关于 单例模式 性能 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信