sleep和wait区别,并且查看线程运行状态

3 篇文章 1 订阅
订阅专栏

一、sleep和wait区别

区别一:语法使用不同

wait 方法必须配合 synchronized 一起使用,不然在运行时就会抛出 IllegalMonitorStateException 的异常

而 sleep 可以单独使用,无需配合 synchronized 一起使用。

区别二:所属类不同

wait 方法属于 Object 类的方法,而 sleep 属于 Thread 类的方法

区别三:唤醒方式不同

sleep 方法必须要传递一个超时时间的参数,且过了超时时间之后,线程会自动唤醒。而 wait 方法可以不传递任何参数,不传递任何参数时表示永久休眠,直到另一个线程调用了 notify 或 notifyAll 之后,休眠的线程才能被唤醒。也就是说 sleep 方法具有主动唤醒功能,而不传递任何参数的 wait 方法只能被动的被唤醒

区别四:释放锁资源不同

wait 方法会主动的释放锁,而 sleep 方法则不会。接下来我们使用代码的方式来演示一下二者的区别。

sleep 不释放锁

接下来使用 sleep 是线程休眠 2s,然后在另一个线程中尝试获取公共锁,如果能够获取到锁,则说明 sleep 在休眠时会释放锁,反之则说明不会释放锁,

在调用了 sleep 之后,在主线程里尝试获取锁却没有成功,只有 sleep 执行完之后释放了锁,主线程才正常的得到了锁,这说明 sleep 在休眠时并不会释放锁。

wait 释放锁

接下来使用同样的方式,将 sleep 替换成 wait,在线程休眠之后,在另一个线程中尝试获取锁,

当调用了 wait 之后,主线程立马尝试获取锁成功了,这就说明 wait 休眠时是释放锁的

区别五:线程进入状态不同

调用 sleep 方法线程会进入 TIMED_WAITING 有时限等待状态,而调用无参数的 wait 方法,线程会进入 WAITING 无时限等待状态。

总结

sleep 和 wait 都可以让线程进入休眠状态,并且它们都可以响应 interrupt 中断,但二者的区别主要体现在:语法使用不同、所属类不同、唤醒方式不同、释放锁不同和线程进入的状态不同。 ​

二、线程的状态Thread.State

三、供参考的多线程代码一、sleep和wait(WAITING和TIMED_WAITING状态)


public class Test04_ThreadState {

    public static void main(String[] args) {
        new Thread(new TimeWaiting(), "TimeWaitingThread").start();
        new Thread(new Waiting(), "WaitingThread").start();

    }
    /**
     * 该线程不断的进行睡眠
     */
    static class TimeWaiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                SleepUtils.second(100);
            }
        }
    }
    /**
     * 该线程在Waiting.class实例上等待
     */
    static class Waiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (Waiting.class) {
                    try {
                        Waiting.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

四、查看线程运行状态的方法

1.jps

获得线程号和线程的类名

2.jstack + 线程号

jstack 2636

看线程某个时刻的运行情况(线程的快照)

这里打印出来的是当前线程的快照dump。

3.jvisualvm(可视化软件)

在java的jdk目录下的bin目录下有jvisualvm.exe文件,可以

打开软件后可以看到正在运行的进程,如下图

可以在其中找到java代码创建的线程的名字对应的线程

可以看到WatingThread线程状态是WAITING,等待状态

TimeWaitingThread线程状态是TIMED_WAITING,超时等待状态

和我们这篇文章的  二、线程的状态Thread.State  对应。

五、案例

一、Blocked阻塞状态

Blocked阻塞状态代码


public class Test04_ThreadState {

    public static void main(String[] args) {
        new Thread(new Blocked(), "BlockedThread-1").start();
        new Thread(new Blocked(), "BlockedThread-2").start();
    }
    
    /**
     * 该线程在Blocked.class实例上加锁后,不会释放该锁
     */
    static class Blocked implements Runnable {
        @Override
        public void run() {
            synchronized (Blocked.class) {
                while (true) {
                    SleepUtils.second(100);
                }
            }
        }
    }
}

Blocked阻塞状态代码jvisualvm查看

由于BlockedThread-1先创建,抢占到了系统资源,运行后拿到了锁,并调用了sleep方法,因此进入TIMED_WAITING超时等待状态,而BlockedThread-2拿不到锁,因此进入Blocked阻塞状态。线程快照dump如下图:

Blocked阻塞状态代码总结

1.触发Blocked状态的原因

由于BlockedThread-1先创建,抢占到了系统资源,运行后拿到了锁,并调用了sleep方法,因此进入TIMED_WAITING超时等待状态,而BlockedThread-2拿不到锁,因此进入BLOCKED阻塞状态。

2.sleep方法

由于sleep方法不会释放锁,因此BlockedThread-2无法拿到锁,进入阻塞状态,更加验证了sleep方法不会释放锁。

二、ReentrantLock可重入锁

ReentrantLock可重入锁代码


public class Test04_ThreadState {

    private static Lock lock = new ReentrantLock();

    public static void main(String[] args) {
        new Thread(new Sync(), "SyncThread-1").start();
        new Thread(new Sync(), "SyncThread-2").start();
    }
   
    static class Sync implements Runnable {

        @Override
        public void run() {
            lock.lock();
            try {
                SleepUtils.second(100);
            } finally {
                lock.unlock();
            }
        }

    }
}

ReentrantLock可重入锁代码jvisualvm查看

ReentrantLock可重入锁代码总结

1.synchronized和ReentrantLock区别(简略描述,之后会详细补充)

ReentrantLock锁更加面向对象
两个锁加锁之后另外一个线程进入状态不一样
synchronized进入BLOCKED状态是被动的 还没有进入到同步代码块中
ReentrantLock是一种主动进入锁的状态 已经进入到代码块中 程序恢复之后 它会从等待的位置继续执行

当SyncThread-2线程进入,而SyncThread-1线程已经拿到锁(lock)
此时SyncThread-2线程会进入WAITING等待状态。

三、有参wait方法和无参wait方法

有参wait方法和无参wait方法代码

public class Test04_ThreadState {

    public static void main(String[] args) {
        new Thread(new Waiting(), "WaitingThread").start();
        new Thread(new WaitingMillisecond(), "WaitingMillisecondThread").start();
    }
  
    /**
     * 该线程在Waiting.class实例上等待,无参wait方法
     */
    static class Waiting implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (Waiting.class) {
                    try {
                        Waiting.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 该线程在Waiting.class实例上等待,有参wait方法,单位为毫秒
     */
    static class WaitingMillisecond implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (WaitingMillisecond.class) {
                    try {
                        WaitingMillisecond.class.wait(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

有参wait方法和无参wait方法代码jvisualvm查看

有参wait方法和无参wait方法代码总结

1.有参wait方法参数单位

有参wait方法参数单位为毫秒

2.有参wait方法和无参wait方法的区别

有参wait方法会进入TIMED_WAITING超时等待状态

无参wait方法会进入WAITING等待状态

四、死锁

死锁代码


public class Test05_DeadLockDemo {

    /** A锁 */
    private static String A = "A";
    /** B锁 */
    private static String B = "B";

    public static void main(String[] args) {
        new Test05_DeadLockDemo().deadLock();
    }

    private void deadLock() {
        Thread t1 = new Thread(()->{
            synchronized (A) {
                SleepUtils.second(2);
                synchronized (B) {
                    System.out.println("1");
                }
            }
        });

        Thread t2 = new Thread(()->{
            synchronized (B) {
                synchronized (A) {
                    System.out.println("2");
                }
            }
        });
        t1.start();
        t2.start();
    }

}

死锁代码jvisualvm查看

死锁代码总结

分析:

t1线程和t2线程同时需要拿到A和B的锁

t1拿到了A锁,t2拿到了B锁

此时t2拿A锁时,A已经被t1线程占用了 ,t2进入阻塞状态

t1拿B锁时,B已经被t2线程占用了 ,t1进入阻塞状态

两个线程都进入阻塞状态,产生死锁问题。

解决办法:

1、避免多次锁定。尽量避免同一个线程进行多次Lock 。

2、使用相同的加锁顺序。如果多个线程需要对多个 Lock 进行锁定,则应该保证它们以相同的顺序请求加锁。

3、使用定时锁。程序在调用 wait() 方法加锁时可指定 timeout 参数,该参数指定超过 timeout 秒后会自动释放对 Lock 的锁定,这样就可以解开死锁了。

4、死锁检测。死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。

五、非守护线程(不使用守护线程方法,这里不算守护线程,只是举例)

非守护线程(不使用守护线程方法)代码

public class Test06_Daemon {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        Thread thread = new Thread(new DeamonRunner());

        thread.start();

        SleepUtils.second(3);
        System.out.println("over");
    }

    //这是条狗--追随主人
    static class DeamonRunner implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
            System.out.println("守护线程开始睡觉");
            try {
                SleepUtils.second(6);
            } finally {
                System.out.println("DeamonRunner 最后执行");
            }
        }
    }
}

非守护线程(不使用守护线程方法)代码执行结果

main
Thread-0
守护线程开始睡觉
over
DeamonRunner 最后执行

进程已结束,退出代码0

非守护线程(不使用守护线程方法)代码总结

当启动非守护线程的进程结束了,非守护线程不会立刻结束,即使启动非守护线程的进程结束了,非守护线程代码也会执行完自己的代码。

六、守护线程(使用守护线程方法,真正的守护线程)

守护线程代码


public class Test06_Daemon {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        Thread thread = new Thread(new DeamonRunner());
        //设置为main线程的守护线程
        thread.setDaemon(true);
        thread.start();

        SleepUtils.second(3);
        System.out.println("over");
    }

    //这是条狗--追随主人
    static class DeamonRunner implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
            System.out.println("守护线程开始睡觉");
            try {
                SleepUtils.second(6);
            } finally {
                System.out.println("DeamonRunner 最后执行");
            }
        }
    }
}

守护线程代码执行结果

main
Thread-0
守护线程开始睡觉
over

进程已结束,退出代码0

守护线程代码总结

使用setDeamon(true)方法,将此线程作为守护线程,守护当前执行体的线程。

此方法必须在线程启动之前调用。

主线程结束了,守护线程也会立刻结束,如果守护线程代码没执行完,守护线程后续没执行的代码也不会再执行。

最后总结:

        a.线程的状态 
            jps看线程的线程号
            jstack看线程某个时刻的运行情况(线程的快照)
            jvisualvm对线程进行dump

        b.线程调用sleep
            进入TIMED_WAITING超时等待状态 不会释放锁
        c.线程调用wait
            调用无参wait方法进入WAITING状态 会释放锁    

            调用有参wait方法,加上等待时间进入TIMED_WAITING超时等待状态 会释放锁    
        d.A线程进入B线程已经拿到锁(synchronized)
            A线程会进入BLOCKED阻塞状态
        e.当A线程进入B线程已经拿到锁(lock)
            A线程会进入WAITING等待状态
        f.synchronized和lock区别
            1.lock锁更加面向对象
            2.两个锁加锁之后另外一个线程进入状态不一样:

                synchronized是BLOCKED状态,lock是WAITING状态
            3.synchronized进入BLOCKED状态是被动的 还没有进入到同步代码块中
            4.lock是一种主动进入锁的状态 已经进入到代码块中 程序恢复之后 它会从等待的位置继续执行

        g.死锁 
            双方各自持有对方需要的锁,不释放 ,双方都处于一种BLOCKED状态
        h.守护线程 
            如果被守护的线程终止 该守护线程也会终止。如果启动非守护线程的进程终止,非守护线程会执行完代码再终止。 

如果你不太理解synchronized锁的对象是什么,你可以看下面这篇文章:

synchronized锁的对象是什么

Java线程sleepwait区别详细介绍
09-05
Java中的多线程是一种抢占式的机制,而不是分时机制。抢占式的机制是有多个线程处于可运行状态,但是只有一个线程运行
JAVA线程sleep()和wait()详解及实例
08-30
本篇文章将详细介绍JAVA线程sleep()和wait()的原理、区别和实现机制,并提供实例代码以便更好地理解这两个方法。 一、sleep()方法 sleep()方法是Thread类的一个静态方法,使得Runnable实现的线程也可以使用sleep...
sleepwait有什么区别
热门推荐
走向资深架构师的旅程
05-20 5万+
第一种解释: 功能差不多,都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步缩.         还有用法的上的不同是:sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来强行打断;wait()可以用notify()直接唤起. 第二种解释: sleep是Thread类的静态方法。
每日一问:sleep() 和 wait() 的区别
最新发布
weixin_44076628的博客
08-13 347
Java 中,sleep()和wait()是两种用于控制线程行为的方法,但它们的功能和用法有显著区别。了解这些差异有助于编写高效的多线程应用程序。是一个静态方法,用于将当前线程暂停执行一段指定的时间。
Java Thread(线程)案例详解sleepwait区别
weixin_30443895的博客
01-16 166
上次对Java Thread有了总体的概述与总结,当然大多都是理论上的,这次我将详解Thread中两个常用且容易疑惑的方法、并通过实例代码进行解疑。。。 F区别 sleep()方法   sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;   sleep()是...
线程wait()和sleep()的区别
林维杰的专栏
12-15 1730
 这两者的施加者是有本质区别的. sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定.好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧.对于运行的主动权是由我的流程来控制. 而wait(),首先,这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是
线程sleep() 方法与 wait() 方法的区别
jiaomubai的博客
06-11 1万+
线程sleep() 方法与 wait() 方法的区别
JAVA线程sleepwait方法区别
aocang4831的博客
11-05 325
sleep线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复,调用sleep 不会释放对象锁。由于没有释放对象锁,所以不能调用里面的同步方法。 sleep()使当前线程进入停滞状态(阻塞当前线程),让出CUP的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会;sleep...
线程sleep、join、yield、wait区别
12-22
它不同于 `sleep()`,因为它不会使线程进入睡眠状态,而是将当前线程运行状态变为可运行状态,这样调度器可能会选择其他线程执行。`yield()` 的效果不是确定的,因为调度器可能会决定继续执行当前线程。通常,`...
线程运行状态
01-20
线程运行状态是多线程编程中的核心概念,它反映了线程在计算机系统中的执行流程。线程,作为程序执行的最小单位,是共享同一内存空间的轻量级进程,它们之间的状态转换对于理解并发执行的机制至关重要。下面将详细...
sleep() 方法和wait()方法的区别.docx
12-23
sleep() 方法和 wait() 方法都是 Java 中的线程控制方法,但是它们有着本质的区别。下面是对这两种方法的详细比较和分析。 sleep() 方法 sleep() 方法是 Thread 类的静态方法,它的主要作用是使当前线程进入停滞...
sleepwait区别
Hello World
11-29 2729
1.所属类不同 sleep()方法属于Thred类,而wait()方法属于Object类 2.持有锁的状态不同 sleep()方法导致了程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持,当指定的时间到了又会自动恢复运行状态。 在调用sleep()方法的过程中,线程不会释放对象锁。 调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备。 3.应用场景不同 sleep可以在任何地方使用,而wait只能在
JAVA面试题解惑系列(十)——话说多线程
weixin_34111790的博客
08-08 432
线程或者说多线程,是我们处理多任务的强大工具。线程和进程是不同的,每个进程都是一个独立运行的程序,拥有自己的变量,且不同进程间的变量不能共享;而线程运行在进程内部的,每个正在运行的进程至少有一个线程,而且不同的线程之间可以在进程范围内共享数据。也就是说进程有自己独立的存储空间,而线程是和它所属的进程内的其他线程共享一个存储空间。线程的使用可以使我们能够并行地处理一些事情。线...
线程sleepwait区别
hanpan123的博客
03-09 1234
http://blog.csdn.net/liuzhenwen/article/details/4202967sleepwait区别有:  1,这两个方法来自不同的类分别是Thread和Object  2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。  3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,...
sleepwait 区别
一个有点理想的博客
05-14 2213
sleepwait区别区别一:所属对象不一样 区别一:对锁的控制权
经典面试题-wait vs sleep
xiaoshiguang3的博客
07-18 613
线程中的waitsleep有何异同点
线程sleepwait区别
Lucky的博客
03-19 428
1、这两个方法来自不同的类分别是Thread和Object 2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。 3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用(使用范围) 4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常 5、sleep是...
写文章

分类专栏

  • JUC 3篇
  • Oracle 1篇
  • 消息中间件 2篇
  • 缓存中间件 4篇
  • 前端 10篇
  • JavaSenior 5篇
  • JavaSE 2篇
  • SSM 24篇
  • 数学 1篇
  • 英语笔记和算法训练 11篇
  • 计算机各种经验 1篇

最新评论

  • mybatis plus框架@TableField注解不生效问题及解决方案

    what_aiyouwei: desc是不是关键字啊

  • Mybatis如何获取自动生成的(主)键值?

    ggyoujian: 提示:order属性设置为AFTER,的获取主键方式容易受到并发干扰;而设置为BEFORE又可能有由于之前没有任何一条插入导致返回为0(条件苛刻的情况下)

  • 如何同时使用多个join——多个连续的left join连接顺序验证

    Ricardo·M·Xu: 如果在c表连接后对b表的查询条件做限制是不是会不生效?

  • 5. RabbitMQ工作模式——RabbitMQ

    张无忌打怪兽: 大佬的文章让我对这领域的技术问题有了更深入的了解,尤其是大佬提到的那些“坑点”,我相信能够在实际应用中避免或解决很多问题。谢谢大佬的分享,期待大佬的更多精彩文章,让我们共同学习、进步。

  • 5. RabbitMQ工作模式——RabbitMQ

    白话机器学习: 优质好文,博主的文章细节到位,内容干货很多,感谢博主的分享,期待博主持续带来更多好文!

大家在看

  • PHP const 和 define主要区别
  • 【运维基础知识】掌握Linux命令行:提升你的系统管理技能 487
  • 大模型的多样性:从语言处理到多模态智能 761
  • Java避坑案例 - 消除代码重复_利用注解 + 反射
  • 程序查询以及软件硬件 80

最新文章

  • Chrome快捷键提高效率
  • Windows工作效率提升快捷键,单屏幕也能当多屏使用
  • 一文带你彻底了解synchronized 和 Lock
2024年14篇
2023年56篇
2022年27篇
2021年7篇
2019年1篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

穗余

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家宜春户外玻璃钢雕塑优势上海节日商场美陈玻璃钢蒙古包雕塑深圳玻璃钢彩绘雕塑商场吊饰美陈上海玻璃钢人物雕塑价格户外玻璃钢雕塑规格哈尔滨动物玻璃钢雕塑公司玻璃钢煎蛋雕塑六安学校玻璃钢雕塑多少钱常宁玻璃钢长颈雕塑玻璃钢雕塑设计专业公司南京玻璃钢卡通雕塑报价玻璃钢雕塑的三大设计要素江苏玻璃钢雕塑厂贺州玻璃钢雕塑作品玻璃钢雕塑卡通哪个比较好国际品牌的玻璃钢雕塑九江水果玻璃钢雕塑苏州玻璃钢花盆设计厂家安庆学校玻璃钢雕塑定制怎么提高商场陈列美陈仙林商场美陈布展盘龙区玻璃钢雕塑代理澳门树脂玻璃钢雕塑昆明人物玻璃钢雕塑供应商青浦区专业玻璃钢雕塑在线咨询玻璃钢雕塑牙膏贵阳玻璃钢雕塑厂哪家好玻璃钢人物泡沫雕塑生产厂家香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化