线程--继承类实现了静态代理模式

1、概述

这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述

(看最后一个图)
进程包含线程;线程是进程的一部分,是轻量级的进程,是不同的执行路径。
多线程:一条路径不能满足要求,另开辟一条路径。
真正的多线程是有多个cpu,有多核。cpu调度哪个程序哪段代码有个调度,调度过程中有个时间片(纳秒级别)。把线程a挂起,再执行线程b,时间片非常的短,看起来像是a和b同时在执行。
什么时候需要执行多线程?
main方法(主线程)执行的时候,还有后台默默执行的gc,这个就是多线程;
异常机制;

2、java实现多线程

就是一些类和接口
这里写图片描述
模拟多线程:

/**
 * 模拟龟兔赛跑
 1、创建多线程  继承  Thread  +重写run(线程体)
 2、使用线程: 创建子类对象 + 对象.start() ,这表示线程启动,线程启动不表示线程运行

 (调用start()方法,加到线程组里面去了。 它内部由cpu去管控它,cpu去调用它。
 而且不要去调用线程类的run方法,那不叫启动线程,而是方法调用。)
    总之:想开辟一条新路径,必须调用start()方法,加到线程组里面,由cpu自己管控。
 * 
 * @author Administrator
 *
 */
public class Rabbit extends Thread {

    @Override
    public void run() {
        //线程体
        for(int i=0;i<100;i++){
            System.out.println("兔子跑了"+i+"步");
        }
    }
}
class Tortoise extends Thread {

    @Override
    public void run() {
        //线程体
        for(int i=0;i<100;i++){
            System.out.println("乌龟跑了"+i+"步");
        }
    }
}


public class RabbitApp {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //创建子类对象
        Rabbit rab = new Rabbit();
        Tortoise tor =new Tortoise();


        //调用start 方法
        rab.start(); //不要调用run方法,这个run方法是内部自己调用
        //rab.run();
        tor.start();
        //tor.run();

        //这里一共是5条路,加上main,后台的gc和异常。

        for(int i=0;i<1000;i++){
            System.out.println("main==>"+i);
        }
    }
}

这里写图片描述

这种方式实现了静态代理模式。run方法不能对外声明异常

package com.bjsxt.thread.create;
/**
 * 静态代理 设计模式
 * 1、真实角色   
 * 2、代理角色: 持有真实角色的引用  (婚介忙前忙后,但结婚的人还是你)
 * 3、二者 实现相同的接口  (你租房子找中介公司、你结婚找婚介)
 * 中介公司帮你找房子,代理角色帮真实角色实现相同的接口
 * @author Administrator
 *
 */
public class StaticProxy {
    /**
     * @param args
     */
    public static void main(String[] args) {
        //创建真实角色,这里没有新增方法,就可以用接口
        Marry you =new You();
        //创建代理角色 + 真实角色的引用(这里可以用set和get方法,也可以用构造器)
        WeddingCompany company =new WeddingCompany(you);
        //执行任务
        company.marry();
    }

}
//接口
interface Marry{
    //void marry();可以省略
    public abstract void marry();
}
//真实角色
class You implements Marry{
    @Override
    public void marry() {
        System.out.println("you and  嫦娥结婚了....");
    }

}
//代理角色
class WeddingCompany implements Marry{
    private Marry you;
    public WeddingCompany() {
    }

    public WeddingCompany(Marry you) {
        this.you = you;
    }
    //注意是私有的
    private void before(){
        System.out.println("布置猪窝....");
    }
    private void after(){
        System.out.println("闹玉兔....");
    }
    @Override
    public void marry() {
        before();
        you.marry();
        after();
    }
}

Thread类实现了Runnable接口,Thread类就是代理角色,我们创建一个真实角色就可以了。
真实角色实现Runnable接口+Thread(Runnable target)代理持有真实角色的引用 = 符合代理模式
源码中:run()方法,如果target!=null,就执行target的run()方法。
代理可以有多个,表示资源可以共享

package com.bjsxt.thread.create;
/**
 * 方便共享资源
 * @author Administrator
 *
 */
public class Web12306 implements Runnable {
    private int num =50;

    @Override
    public void run() {
        while(true){
            if(num<=0){
                break; //跳出循环
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        }
    }

    public static void main(String[] args) {
        //真实角色
        Web12306 web = new Web12306();
        //代理
        Thread t1 =new Thread(web,"路人甲");
        Thread t2 =new Thread(web,"黄牛已");
        Thread t3 =new Thread(web,"攻城师");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

创建多线程总结:
这里写图片描述

这里写图片描述

package com.bjsxt.thread.create;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * 使用Callable创建线程
 * @author Administrator
 *
 */
public class Call {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //创建线程
        ExecutorService  ser=Executors.newFixedThreadPool(2);
        Race tortoise = new Race("老不死",1000);
        Race rabbit = new Race("小兔子",500);
        //获取值
        Future<Integer> result1 =ser.submit(tortoise) ;
        Future<Integer> result2 =ser.submit(rabbit) ;

        Thread.sleep(2000); //2秒
        tortoise.setFlag(false); //停止线程体循环
        rabbit.setFlag(false);

        int num1 =result1.get();
        int num2 =result2.get();
        System.out.println("乌龟跑了-->"+num1+"步");
        System.out.println("小兔子跑了-->"+num2+"步");
        //停止服务 
        ser.shutdownNow();

    }
}

class Race implements Callable<Integer>{
    private String name ; //名称
    private long time; //延时时间
    private boolean flag =true;
    private int step =0; //步
    public Race() {
    }   

    public Race(String name) {
        super();
        this.name = name;
    }
    public Race(String name,long time) {
        super();
        this.name = name;
        this.time =time;
    }

    @Override
    public Integer call() throws Exception {
        while(flag){
            Thread.sleep(time); //延时
            step++;
        }
        return step;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }



    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getStep() {
        return step;
    }

    public void setStep(int step) {
        this.step = step;
    }

}
3、线程状态

start()之后 线程进入就绪状态,等待CPU调度
就绪,运行,阻塞状态 都是线程是 活的,其余的都是死的,new出来没有启动也是死的。

这里写图片描述

创建状态:new一下即可
就绪状态:调用start就进入就绪了
运行状态:cpu调度了

终止:线程体执(run方法)行完毕。 下面看线程怎么停止
这里写图片描述

这里写图片描述

package com.bjsxt.thread.status;

public class StopDemo01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Study s =new Study();
        new Thread(s).start();

        //外部干涉
        for(int i=0;i<100;i++){
            if(50==i){ //外部干涉
                s.stop();
            }
            System.out.println("main.....-->"+i);
        }
    }
}
class Study implements Runnable{
     //1)、线程类中 定义 线程体使用的标识   
    private boolean flag =true;
    @Override
    public void run() {
        //2)、线程体使用该标识
        while(flag){
            System.out.println("study thread....");
        }
    }
    //3)、对外提供方法改变标识
    public void stop(){
        this.flag =false;
    }
}

这里写图片描述
阻塞:

join:合并线程. (等合进来的运行完了。)
主线程中插一个 线程t,t.join表示,线程t合入到主线程中,等t执行完了再执行主线程,和方法调用效果一样。

package com.bjsxt.thread.status;
/**
 * join:合并线程
 * @author Administrator
 *
 */
public class JoinDemo01 extends Thread {

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        JoinDemo01 demo = new JoinDemo01();
        Thread t = new Thread(demo); //新生成的线程
        t.start();//就绪
        //cpu调度 运行


        for(int i=0;i<1000;i++){
            if(50==i){
                t.join(); //main阻塞...    等于50的时候,让demo执行完毕,再执行main线程
            }
            System.out.println("main...."+i);
        }
    }

    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("join...."+i);
        }
    }

}

yield:暂停自己的线程(后面可能还会被调度),(静态方法)(写在谁的线程体里面就暂定谁) (让合进来的运行一会儿)

package com.bjsxt.thread.status;

public class YieldDemo01 extends Thread {

    /**
     * @param args
     */
    public static void main(String[] args) {
        YieldDemo01 demo = new YieldDemo01();
        Thread t = new Thread(demo); //新生
        t.start();//就绪
        //cpu调度 运行


        for(int i=0;i<1000;i++){
            if(i%20==0){
                //暂停本线程 main
                Thread.yield();
            }
            System.out.println("main...."+i);
        }
    }

    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("yield...."+i);
        }
    }

}

sleep:休眠,(静态方法)不释放锁。
倒计时:

package com.bjsxt.thread.status;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 倒计时
 * 1、倒数10个数,一秒内打印一个
 * 2、倒计时
 * @author Administrator
 *
 */
public class SleepDemo01 {
    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        Date endTime =new Date(System.currentTimeMillis()+10*1000);
        long end =endTime.getTime();
        while(true){
            //输出
            System.out.println(new SimpleDateFormat("mm:ss").format(endTime));  //format格式化为字符串,parse转换为日期
            //等待一秒,顺序也可以放在下面
            Thread.sleep(1000);
            //构建下一秒时间
            endTime =new Date(endTime.getTime()-1000);
            //10秒以内 继续 否则 退出
            if(end-10000>endTime.getTime()){
                break;
            }
        }
    }
    public static void test1() throws InterruptedException{
        int num =10;
        while(true){
            System.out.println(num--);
            Thread.sleep(1000); //暂停
            if(num<=0){
                break;
            }
        }
    }
}

网络延迟:

package com.bjsxt.thread.status;


/**
 * Sleep模拟 网络延时  线程不安全的类
 * @author Administrator
 *
 */
public class SleepDemo02 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //真实角色
        Web12306 web= new Web12306();
        Web12306 web2 = new Web12306();
        //代理
        Thread t1 =new Thread(web,"路人甲");
        Thread t2 =new Thread(web,"黄牛已");
        Thread t3 =new Thread(web,"攻城师");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }

}

class Web12306 implements Runnable {
    private int num =50;

    @Override
    public void run() {
        while(true){
            if(num<=0){
                break; //跳出循环
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        }
    }
}

线程状态:
这里写图片描述

设置优先级
/**
 * 优先级:概率,不是绝对的先后顺序
   MAX_PRIORITY  10
   NORM_PRIORITY 5 (默认)
   MIN_PRIORITY  1

   setPriority()
   getPriority()
 * @author Administrator
 *
 */
4、线程同步:

这里写图片描述
这里写图片描述
java.util.Hashtable - 线程安全的,同步的
StringBuffer – 也是线程安全的,使用了synchronized。这个关键字就是锁,任何线程访问这个方法,先获得这个方法的锁,锁住了门一关别人就访问不了
等线程锁释放了,别的锁才能进来。线程体执行完毕,锁自然就释放了。
访问同一个资源才会有并发问题,访问不同的资源没事。
一般地线程不安全的效率比较高。
JDK的RunTime就是单例中饿汉

package com.bjsxt.thread.syn;


public class SynDemo01 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        //真实角色
        Web12306 web= new Web12306();
        //代理
        Thread t1 =new Thread(web,"路人甲");
        Thread t2 =new Thread(web,"黄牛已");
        Thread t3 =new Thread(web,"攻城师");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}
/**
 * 线程安全的类
 * @author Administrator
 *
 */
class Web12306 implements Runnable {
    private int num =10;
    private boolean flag =true;
    @Override
    public void run() {
        while(flag){
            test5();
        }
    }

    //线程不安全 锁定范围不正确
    public void test6(){

        if(num<=0){
            flag=false; //跳出循环
            return ;
        }
         //a  b  c  
        synchronized(this){
            try {
                Thread.sleep(500); //模拟 延时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        }
    }

    //线程不安全  锁定资源不正确
    public void test5(){
        //a  b  c
        synchronized((Integer)num){
            if(num<=0){
                flag=false; //跳出循环
                return ;
            }
            try {
                Thread.sleep(500); //模拟 延时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        }
    }



    //锁定范围不正确 线程不安全
    //锁定范围小了
    public void test4(){
        //   c  1
        synchronized(this){
            //b
            if(num<=0){
                flag=false; //跳出循环
                return ;
            }
        }
        // b
        try {
            Thread.sleep(500); //模拟 延时
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
    }//a -->1

    //线程安全  锁定正确
    public void test3(){
        //a  b  c   abc进来只能是依次地等待
        //锁定this,this指的是对象
        synchronized(this){
            if(num<=0){
                flag=false; //跳出循环
                return ;
            }
            try {
                Thread.sleep(500); //模拟 延时
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
        }
    }
    //线程安全  锁定正确
    public synchronized void test2(){
        if(num<=0){
            flag=false; //跳出循环
            return ;
        }
        try {
            Thread.sleep(500); //模拟 延时
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
    }

    //线程不安全
    public void test1(){
        if(num<=0){
            flag=false; //跳出循环
            return ;
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"抢到了"+num--);
    }
}
package com.bjsxt.thread.syn;
/**
 * 单例设计模式:确保一个类只有一个对象
 这个对象由类内部创建,外部只能使用这一个对象(JVM只有一个吧,其它类都是对它的引用)
 GC..
 * @author Administrator
 *
 */
public class SynDemo02 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        JvmThread thread1 = new JvmThread(100);
        JvmThread thread2 = new JvmThread(500);
        thread1.start();
        thread2.start();
    }
}

class JvmThread extends Thread{
    private long time;
    public JvmThread() {
    }
    public JvmThread(long time) {
        this.time =time;
    }
    @Override
    public void run() {     
        System.out.println(Thread.currentThread().getName()+"-->创建:"+Jvm.getInstance(time));
    }
}


/**
 * 单例设计模式(的套路)
 * 确保一个类只有一个对象
 * 懒汉式  double checking(经典的双重检查)
 * 1、构造器私有化,避免外部直接创建对象
 * 2、声明一个私有的静态变量
 * 3、创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
 */
class Jvm {
    //声明一个私有的静态变量
    private static Jvm instance =null;    //懒得去创建对象
    //构造器私有化,避免外部直接创建对象
    private Jvm(){

    }
    //对getInstance3的改进
    //创建一个对外的公共的静态方法 访问该变量,如果变量没有对象,创建该对象
    public static Jvm getInstance(long time){
        // c d e  -->效率  提供 已经存在对象的访问效率(线程不需要等待)
        if(null==instance){ 
            // a b 。a创建了,b进来发现有对象了,就不必等其他线程拿到对象之后它才可以拿,b直接拿对象就行
            synchronized(Jvm.class){
                if(null==instance ){
                    try {
                        Thread.sleep(time); //延时 ,放大错误。才会加一个time
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance =new Jvm();
                }
            }
      }//a
      return instance;
    }

    //这里是同步块
    public static Jvm getInstance3(long time){
        //a b c d e  -->效率不高 c  存在对象也需要等待
        //任何时候要获取对象,如果对象存在的话,那也要进下面的方法,也要等待。锁定的是对象,线程b必须等线程a拿到对象之后才可以拿对象,有了一个等待的时间
        //这里不能用this,因为静态方法里面没有this
        synchronized(Jvm.class){
            if(null==instance ){
                try {
                    Thread.sleep(time); //延时 ,放大错误
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                instance =new Jvm();
            }
            return instance;
        }
    }

    //这里是同步方法
    public static synchronized Jvm getInstance2(long time){
        if(null==instance ){
            try {
                Thread.sleep(time); //延时 ,放大错误
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance =new Jvm();
        }
        return instance;
    }

    //问题:单线程里面new出来的始终是一个对象,多线程的话就要加synchronized
    public static Jvm getInstance1(long time){
        if(null==instance ){
            try {
                Thread.sleep(time); //延时 ,放大错误
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //两个线程进来,就有可能创建两个对象
            instance =new Jvm();
        }
        return instance;
    }
}
package com.bjsxt.thread.syn;
/**
 * 单例创建的方式
 * 1、懒汉式
 * 1)、构造器私有化
 * 2)、声明私有的静态属性
 * 3)、对外提供访问属性的静态方法,确保该对象存在
 * 
 * @author Administrator
 *
 */
 //懒汉式
public class MyJvm {
    private static MyJvm instance;
    private MyJvm(){

    }
    //多线程的难点:又要提高效率,又要注意安全
    public static MyJvm getInstance (){
        if(null==instance){ //提供效率
            synchronized(MyJvm.class){
                if(null==instance){ //安全
                    instance =new MyJvm();
                }
            }
        }
        return instance;
    }
}
/**
 * 饿汉式
   1)、构造器私有化 
 * 2)、声明私有的静态属性,同时创建该对象
 * 3)、对外提供访问属性的静态方法
 * @author Administrator
 *
 */
class MyJvm2 {
    //这里是线程安全的,
    //加载MyJvm2的时候instance就初始化
    private static MyJvm2 instance =new MyJvm2();
    private MyJvm2(){

    }
    public static MyJvm2 getInstance (){        
        return instance;
    }

}
/**
 * 类在使用的时候加载 ,延缓加载时间
 * @author Administrator
 *
 */
class MyJvm3 { //对MyJvm2的改进,提升效率的
    //内部类   
    //加载MyJvm3的时候不一定会加载JVMholder,只有用到的时候(这里是调用getInstance时)加载。不调用该方法,JVMholder永远不会被加载
    //可以延缓加载时间
    private static class JVMholder{
        private static MyJvm3 instance =new MyJvm3();
    }
    private MyJvm3(){

    }
    public static MyJvm3 getInstance (){        
        return JVMholder.instance;
    }

}

死锁:过多的同步造成死锁
即:不给我钱我不给你货,你不给我货我就不给你钱
同一份资源,在线程A中用了,又在线程B中用了,就可能会造成死锁。互相不释放

package com.bjsxt.thread.syn;
/**
 * 过多的同步方法可能造成死锁
 * @author Administrator
 *
 */
public class SynDemo03 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Object g =new Object();
        Object m = new Object();
        Test t1 =new Test(g,m);
        Test2 t2 = new Test2(g,m);
        Thread proxy = new Thread(t1);  //多态不能调用新增方法
        Thread proxy2 = new Thread(t2);
        proxy.start();
        proxy2.start();
    }

}
class Test implements Runnable{
    Object goods ;
    Object money ;

    public Test(Object goods, Object money) {
        super();
        this.goods = goods;
        this.money = money;
    }

    @Override
    public void run() {
        while(true){
            test();
        }
    }

    public void test(){
        synchronized(goods){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(money){

            }
        }
        System.out.println("一手给钱");
    }
}

class Test2  implements Runnable{
    Object goods ;
    Object money ;
    public Test2(Object goods, Object money) {
        super();
        this.goods = goods;
        this.money = money;
    }

    @Override
    public void run() {
        while(true){
            test();
        }
    }

    public void test(){
        synchronized(money){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(goods){    
            }
        }
        System.out.println("一手给货");
    }
}

生产者消费者模式(不是设计模式,是解决多线程的问题)
如何解决死锁,看看生产者消费者模式。
先生产再消费,有东西了再消费,没有东西先生产(用的是同一份资源)
这里写图片描述

package com.bjsxt.thread.pro;
/**
 一个场景,共同的资源
  生产者消费者模式 信号灯法
 wait() :等待,释放锁  。 sleep 不释放锁
 notify()/notifyAll():唤醒
   他俩必须要与 synchronized一起使用
 * @author Administrator
 *
 */
public class Movie {
    private String pic ;
    //信号灯
    //flag -->T 生产生产,消费者等待 ,生产完成后通知消费
    //flag -->F 消费者消费 生产者等待, 消费完成后通知生产
    private boolean flag =true;
    /**
     * 播放
     * @param pic
     */
    public synchronized void play(String pic){
        if(!flag){ //生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //开始生产
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("生产了:"+pic);  //生产了左青龙
        //生产完毕      
        this.pic =pic;
        //通知消费
        this.notify();
        //生产者停下
        this.flag =false;
    }

    public synchronized void watch(){
        if(flag){ //消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //开始消费
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("消费了"+pic);
        //消费完毕
        //通知生产
        this.notifyAll();
        //消费停止
        this.flag=true;
    }
}
5、任务调度

这里写图片描述

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
    了解
  Timer() 
  schedule(TimerTask task, Date time) 
  schedule(TimerTask task, Date firstTime, long period) 
  自学 quartz
 * @author Administrator
 *
 */
public class TimeDemo01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Timer timer =new Timer();
        timer.schedule(new TimerTask(){

            @Override
            public void run() {
                System.out.println("so easy....");
            }}, new Date(System.currentTimeMillis()+1000), 200);
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值