汪文君高并发编程总结-第一阶段

汪文君高并发编程总结-第一阶段

例子1-线程的创建

public class TryConcurrency {

    public static void main(String[] args) {
        Thread t = new Thread("READ-Thread") {
            @Override
            public void run() {
                println(Thread.currentThread().getName());//main
                readFromDataBase();
            }
        };

        t.start();

        new Thread("WRITE-Thread") {
            @Override
            public void run() {
                writeDataToFile();
            }
        }.start();
    }

    private static void readFromDataBase() {
        //read data from database and handle it.
        try {
            println("Begin read data from db.");
            Thread.sleep(1000 * 30L);
            println("Read data done and start handle it.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        println("The data handle finish and successfully.");
    }

    private static void writeDataToFile() {
        try {
            println("Begin write data to file.");
            Thread.sleep(2000 * 20L);
            println("Write data done and start handle it.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        println("The data handle finish and successfully.");
    }

    private static void println(String message) {
        System.out.println(message);
    }
}

例子2-Tread类的模板方法

public class TemplateMethod {

    public final void print(String message) {
        System.out.println("################");
        wrapPrint(message);
        System.out.println("################");
    }

    protected void wrapPrint(String message) {

    }

    public static void main(String[] args) {
        TemplateMethod t1 = new TemplateMethod(){
            @Override
            protected void wrapPrint(String message) {
                System.out.println("*"+message+"*");
            }
        };
        t1.print("Hello Thread");

        TemplateMethod t2 = new TemplateMethod(){
            @Override
            protected void wrapPrint(String message) {
                System.out.println("+"+message+"+");
            }
        };

        t2.print("Hello Thread");

    }
}

1.Java应用程序的main函数是一个线程,是被JVM启动的时候调用,线程的名字叫main

2.实现一个线程,必须创建Thread实例,override run方法,并且调用start方法

3.在jvm启动后实际上有多个线程,但是至少有一个非守护线程

4.当你调用一个线程start方法的时候,此时至少有两个线程,一个是调用你的线程,还有一个是启动的线程

5.线程的生命周期分为new,runnable,running,block,terminated

例子3

多线程银行窗口排号的例子

  • 版本V1
public class TicketWindow extends Thread {
    private String name;

    private final static Integer MAX = 50;

    private  Integer i = 1;

    public TicketWindow(String name ) {
        this.name = name;
    }

    @Override
    public void run() {
        while (i <= MAX) {
            System.out.println(name+"号码为:"+i++);
        }
    }
}
public class Back {
    public static void main(String[] args) {
        TicketWindow t1 = new TicketWindow("窗口1");
        t1.start();

        TicketWindow t2 = new TicketWindow("窗口2");
        t2.start();
        TicketWindow t3 = new TicketWindow("窗口3");
        t3.start();
    }
}

V1版本显然满足不了需求

  • 升级版本V2
public class TicketWindowV2 implements Runnable {

    private final static Integer MAX = 50;

    private Integer index = 1;

    @Override
    public void run() {
        while (index <= MAX) {
            System.out.println(Thread.currentThread() + " 的号码为:" + index++);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class BackV2 {
    public static void main(String[] args) {
        final TicketWindowV2 windowV2 = new TicketWindowV2();

        Thread t1 = new Thread(windowV2,"窗口1");
        Thread t2 = new Thread(windowV2,"窗口2");
        Thread t3 = new Thread(windowV2,"窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

V2运行结果:

Thread[窗口1,5,main] 的号码为:1
Thread[窗口3,5,main] 的号码为:2
Thread[窗口2,5,main] 的号码为:1
Thread[窗口3,5,main] 的号码为:3
Thread[窗口1,5,main] 的号码为:4
Thread[窗口2,5,main] 的号码为:5
Thread[窗口1,5,main] 的号码为:6
Thread[窗口3,5,main] 的号码为:7
Thread[窗口2,5,main] 的号码为:8
Thread[窗口2,5,main] 的号码为:9
Thread[窗口3,5,main] 的号码为:11
Thread[窗口1,5,main] 的号码为:10
Thread[窗口2,5,main] 的号码为:12
Thread[窗口3,5,main] 的号码为:12
Thread[窗口1,5,main] 的号码为:13
Thread[窗口1,5,main] 的号码为:14
Thread[窗口2,5,main] 的号码为:16
Thread[窗口3,5,main] 的号码为:15
Thread[窗口1,5,main] 的号码为:17
Thread[窗口2,5,main] 的号码为:19
Thread[窗口3,5,main] 的号码为:18
Thread[窗口1,5,main] 的号码为:20
Thread[窗口2,5,main] 的号码为:21
Thread[窗口3,5,main] 的号码为:22
Thread[窗口2,5,main] 的号码为:23
Thread[窗口3,5,main] 的号码为:25
Thread[窗口1,5,main] 的号码为:24
Thread[窗口1,5,main] 的号码为:26
Thread[窗口3,5,main] 的号码为:27
Thread[窗口2,5,main] 的号码为:28
Thread[窗口1,5,main] 的号码为:29
Thread[窗口3,5,main] 的号码为:30
Thread[窗口2,5,main] 的号码为:30
Thread[窗口3,5,main] 的号码为:31
Thread[窗口1,5,main] 的号码为:32
Thread[窗口2,5,main] 的号码为:31
Thread[窗口3,5,main] 的号码为:32
Thread[窗口2,5,main] 的号码为:33
Thread[窗口1,5,main] 的号码为:33
Thread[窗口1,5,main] 的号码为:34
Thread[窗口2,5,main] 的号码为:35
Thread[窗口3,5,main] 的号码为:34
Thread[窗口2,5,main] 的号码为:36
Thread[窗口1,5,main] 的号码为:37
Thread[窗口3,5,main] 的号码为:37
Thread[窗口1,5,main] 的号码为:38
Thread[窗口2,5,main] 的号码为:39
Thread[窗口3,5,main] 的号码为:40
Thread[窗口1,5,main] 的号码为:41
Thread[窗口2,5,main] 的号码为:41
Thread[窗口3,5,main] 的号码为:42
Thread[窗口1,5,main] 的号码为:43
Thread[窗口2,5,main] 的号码为:44
Thread[窗口3,5,main] 的号码为:45
Thread[窗口2,5,main] 的号码为:46
Thread[窗口1,5,main] 的号码为:46
Thread[窗口3,5,main] 的号码为:47
Thread[窗口1,5,main] 的号码为:48
Thread[窗口2,5,main] 的号码为:48
Thread[窗口3,5,main] 的号码为:49
Thread[窗口1,5,main] 的号码为:50
Thread[窗口2,5,main] 的号码为:51

可以看到叫的号可能会重复,最后拿到的号也大于50了

例子4-用策略模式实现计算器

@FunctionalInterface
public interface CalculatorStrategy {
    double calculator(double salary,double bonus);
}
public class CalculatorStrategyImpl implements CalculatorStrategy {
    private final static double SALARY_RATE = 0.1;
    private final static double BONUS_RATE = 0.15;
    @Override
    public double calculator(double salary, double bonus) {
        return salary*SALARY_RATE+BONUS_RATE*bonus;
    }
}
public class TaxCalculator {
    private final double salary;
    private final double bonus;

    private  CalculatorStrategy calculatorStrategy;

    public TaxCalculator(double salary, double bonus, CalculatorStrategy calculatorStrategy) {
        this.salary = salary;
        this.bonus = bonus;
        this.calculatorStrategy = calculatorStrategy;
    }
    public TaxCalculator(double salary, double bonus) {
        this.salary = salary;
        this.bonus = bonus;
    }
    public double calculate(){
        return this.calcTax();
    }

    protected double calcTax() {
        return calculatorStrategy.calculator(salary,bonus);
    }

    public void setCalculatorStrategy(CalculatorStrategy calculatorStrategy) {
        this.calculatorStrategy = calculatorStrategy;
    }

    public double getSalary() {
        return salary;
    }

    public double getBonus() {
        return bonus;
    }
}
public class TaxCalculatorMain {
    public static void main(String[] args) {

        TaxCalculator taxCalculator = new TaxCalculator(10000d, 2000d);
        CalculatorStrategy strategy = new CalculatorStrategyImpl();
        taxCalculator.setCalculatorStrategy(strategy);
        System.out.println(taxCalculator.calculate());
        //采用Java8
        TaxCalculator taxCalculator2 = new TaxCalculator(10000d, 2000d, (a, b) -> a * 0.1 + b * 0.15);
        System.out.println(taxCalculator2.calculate());
    }
}

例子5

// 线程的创建,线程名称自增规则,命名方式
public class CreateThread {
    public static void main(String[] args) {
        Thread t1 = new Thread();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                System.out.println("==========");
            }
        };
        t1.start();
        t2.start();
        System.out.println(t1.getName());
        System.out.println(t2.getName());

        Thread t3 = new Thread("MyName");
        Thread t4 = new Thread(() -> {
            System.out.println("Runnable...");
        });

        System.out.println(t3.getName());
        System.out.println(t4.getName());

        Thread t5 = new Thread(() -> {
            System.out.println("Runnable..." + Thread.currentThread().getName());
        }, "RunnableThread");

        t5.start();
    }
}
public class CreateThread2 {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t.start();
        System.out.println("==================");
        System.out.println(t.getThreadGroup());//java.lang.ThreadGroup[name=main,maxpri=10]
        System.out.println(Thread.currentThread().getName());//main
        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
        System.out.println(threadGroup.getName());//main
        System.out.println("==================");
        System.out.println(threadGroup.activeCount());//3

        Thread[] threads = new Thread[threadGroup.activeCount()];
        threadGroup.enumerate(threads);

        Arrays.asList(threads).forEach(System.out::println);
        //Thread[main,5,main]
        //Thread[Monitor Ctrl-Break,5,main]
        //Thread[Thread-0,5,]
    }
}
public class CreateThread3 {

    private int i = 0;

    private byte[] bytes = new byte[1024];

    private static int counter = 0;

    //JVM will create a thread named "main"
    public static void main(String[] args) {
        //create a JVM stack
        try {
            add(0);
        } catch (Error e) {
            e.printStackTrace();
            System.out.println(counter); //31457
        }
    }

    private static void add(int i) {
        ++counter;
        add(i + 1);
    }
   
}
public class CreateThread4 {

    private static int counter = 1;

    public static void main(String[] args) {

        Thread t1 = new Thread(null, new Runnable() {
            @Override
            public void run() {
                try {
                    add(1);
                } catch (Error e) {
                    System.out.println(counter);
                }
            }

            private void add(int i) {
                counter++;
                add(i + 1);
            }
        }, "Test", 1 << 24);
        t1.start();
        //260419
    }
}
public class CreateThread5 {

    private static int counter = 1;

    public static void main(String[] args) {

        try {
            for (int i = 0; i < 1000; i++) {
                counter++;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            add(1);
                        } catch (Error e) {
//                            System.out.println(counter);
                        }
                    }

                    private void add(int i) {

                        add(i + 1);
                    }
                }).start();
            }
        } catch (Error e) {
            counter++;
        }
        System.out.println("Total created thread nums=>" + counter);
    }
}

总结:

1、创建线程对象Thread,默认有一个线程名,以Thread-开头,从0开始计数

2、如果在构造Thread的时候没有传递Runnable或者没有复写Thread的run方法,该Thread将不会调用任何东西,如果传递了Runnable
接口的实例,或者复写了Thread的run方法,则会执行该方法的逻辑单元

3、如果构造线程对象时未传入ThreadGroup,Thread会默认获取父线程的ThreadGroup作为该线程的ThreadGroup,此时
子线程和父线程将会在同一个ThreadGroup中

4、构造Thread的时候传入stackSize代表着该线程占用的stack大小,如果没有指定stacksize的大小,
默认是0,0代表着会忽略该参数,该参数会被JNI函数去使用 。需要注意:该参数有一些平台有效,在有些平台则无效

例子6-守护线程

//守护线程

/**
 * A<---------------------------------->B
 *  ->daemonThread(health check)
 * */
public class DaemonThread {

    public static void main(String[] args) throws InterruptedException {

        Thread t = new Thread() {

            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread().getName() + " running");
                    Thread.sleep(100000);
                    System.out.println(Thread.currentThread().getName() + " done.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }; //new
        t.setDaemon(true);
        //runnable  ->running| ->dead| ->blocked
        t.start();


        Thread.sleep(5_000);   //JDK1.7
        System.out.println(Thread.currentThread().getName());
    }
}
public class DaemonThread2 {
    public static void main(String[] args) {

        Thread t = new Thread(() -> {
            Thread innerThread = new Thread(() -> {
                try {
                    while (true) {
                        System.out.println("Do some thing for health check.");
                        Thread.sleep(1_000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });

//            innerThread.setDaemon(true); 设置为守护线程,该线程会关闭
            innerThread.start();

            try {
                Thread.sleep(1_000);
                System.out.println("T thread finish done.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //t.setDaemon(true);
        t.start();


    }
}
public class ThreadSimpleAPI {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            Optional.of("Hello").ifPresent(System.out::println);
            try {
                Thread.sleep(100_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1");

        t.start();
        Optional.of(t.getName()).ifPresent(System.out::println);
        Optional.of(t.getId()).ifPresent(System.out::println);
        Optional.of(t.getPriority()).ifPresent(System.out::println);
    }
}
//输出
t1
Hello
12
5
//线程优先级(并不是严格按照高中低执行的)
public class ThreadSimpleAPI2 {

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
            }
        });
        t1.setPriority(Thread.MAX_PRIORITY);

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
            }
        });

        t2.setPriority(Thread.NORM_PRIORITY);

        Thread t3 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                Optional.of(Thread.currentThread().getName() + "-Index" + i).ifPresent(System.out::println);
            }
        });

        t3.setPriority(Thread.MIN_PRIORITY);

        t1.start();
        t2.start();
        t3.start();
    }
}

例子7-join()

//join :join的线程全部运行完之后,别的线程才会开始运行
public class ThreadJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            IntStream.range(1, 1000)
                    .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
        });
        Thread t2 = new Thread(() -> {
            IntStream.range(1, 1000)
                    .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        Optional.of("All of tasks finish done.").ifPresent(System.out::println);
        IntStream.range(1, 1000)
                .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));
    }
}
//join(long millis, int nanos)
public class ThreadJoin2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                System.out.println("t1 is running");
                Thread.sleep(10_000);
                System.out.println("t1 is done");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        t1.join(100,10);


        Optional.of("All of tasks finish done.").ifPresent(System.out::println);
        IntStream.range(1, 1000)
                .forEach(i -> System.out.println(Thread.currentThread().getName() + "->" + i));

        //start httpServer
//        JettyHttpServer.start();

//        Thread.currentThread().join();

//        Thread t1 = new Thread(() -> {
//
//            System.out.println("t1 is running");
//            while (true) {
//                System.out.println(Thread.currentThread().isInterrupted());
//            }
//        });
//        t1.start();
//        Thread t2 = new Thread(() -> {
//            try {
//                Thread.sleep(10000);
//                t1.interrupt();
//                System.out.println("interrupt");
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//        });
//        t2.start();
//
//        try {
//            t1.join(1000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }


    }
}

用join()写的一个例子:三个机器全部运行完成输出打印结果。

public class ThreadJoin3 {

    public static void main(String[] args) throws InterruptedException {
        long startTimestamp = System.currentTimeMillis();
        Thread t1 = new Thread(new CaptureRunnable("M1", 10000L));
        Thread t2 = new Thread(new CaptureRunnable("M2", 30000L));
        Thread t3 = new Thread(new CaptureRunnable("M3", 15000L));

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();

        long endTimestamp = System.currentTimeMillis();
        System.out.printf("Save data begin timestamp is:%s, end timestamp is:%s\n", startTimestamp, endTimestamp);
    }

}

class CaptureRunnable implements Runnable {

    private String machineName;

    private long spendTime;

    public CaptureRunnable(String machineName, long spendTime) {
        this.machineName = machineName;
        this.spendTime = spendTime;
    }

    @Override
    public void run() {
        //do the really capture data.
        try {
            Thread.sleep(spendTime);
            System.out.printf(machineName + " completed data capture at timestamp [%s] and successfully.\n", System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public String getResult() {
        return machineName + " finish.";
    }
}

例子8-interrupt()

public class ThreadService {
    private Thread executeThread;
    private boolean finished = false;

    public void execute(Runnable task){
        executeThread = new Thread(() -> {
            Thread runner =  new Thread(task);
            runner.setDaemon(true);
            runner.start();
            try {
                runner.join();
                finished = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        executeThread.start();
    }
    public void shutdown(long mills){
        long currentTime = System.currentTimeMillis();
        while (!finished){
            if ((System.currentTimeMillis() - currentTime) >= mills){
                System.out.println("任务超时,需要结束它");
                executeThread.interrupt();
                break;
            }
            try {
                executeThread.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("执行线程被打断!");
                break;
            }
        }
        finished = false;
    }

}
//线程强制关闭
public class ThreadCloseForce {
    public static void main(String[] args) {
        ThreadService service = new ThreadService();
        long start = System.currentTimeMillis();
        service.execute(()->{
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        service.shutdown(10000);
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

}
//优雅的关闭
public class ThreadCloseGraceful {
    private static class Worker extends Thread{
        private volatile boolean start = true;
        @Override
        public void run() {
            while (start){
                //
            }
        }
        public void shutdown(){
            this.start = false;
        }
    }

    public static void main(String[] args) {
        Worker worker = new Worker();
        worker.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        worker.shutdown();
    }
}
//优雅的关闭2
public class ThreadCloseGraceful2 {
    private static class Worker extends Thread {
        @Override
        public void run() {
            while (true) {
                if (Thread.interrupted()) {
                    break;
                }
            }
        }

    }

    public static void main(String[] args) {
        Worker worker = new Worker();
        worker.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        worker.interrupt();
    }
}
//interrupt的例子
public class ThreadInterrupt {

    private static final Object MONITOR = new Object();

    public static void main(String[] args) throws InterruptedException {

       /* Thread t = new Thread() {
            @Override
            public void run() {
                while (true) {
                    synchronized (MONITOR) {
                        try {
                            MONITOR.wait(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            System.out.println(isInterrupted());
                        }
                    }
                }
            }
        };

        t.start();
        Thread.sleep(100);
        System.out.println(t.isInterrupted());//false
        t.interrupt();
        System.out.println(t.isInterrupted());//true

        t.stop();*/

//        Thread t = new Thread(() -> {
//            while (true) {
//                synchronized (MONITOR) {
//                    try {
//                        MONITOR.wait(10);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                        System.out.println(Thread.interrupted());
//                    }
//                }
//            }
//        });
            Thread t = new Thread() {
                @Override
                public void run() {
                    while (true) {

                    }
                }
            };

        t.start();
        Thread main = Thread.currentThread();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                main.interrupt();
                System.out.println("interrupt");
            }
        };

        t2.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //---------------------------


    }
}

例子9

1、//this锁 锁住的是当前类

public class SynchronizedThis {
    public static void main(String[] args) {
        ThisLock thisLock = new ThisLock();
        new Thread(()-> thisLock.m1()).start();
        new Thread(()->thisLock.m2()).start();
    }
}
class ThisLock{
    private final Object LOCK = new Object();
    public void m1(){
        synchronized (this){
            try {
                System.out.println(Thread.currentThread().getName()+this.getClass());
                Thread.sleep(10_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void m2(){
        synchronized (this){
            try {
                System.out.println(Thread.currentThread().getName()+this.getClass());
                Thread.sleep(10_000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2、//synchronized 测试类 顺序执行

public class SynchronizedTest {

    private final static Object LOCK = new Object();

    public static void main(String[] args) {

        Runnable runnable = () -> {
            synchronized (LOCK) {
                try {
                    Thread.sleep(2_000);
                    System.out.println(Thread.currentThread());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);
        t1.start();
        t2.start();
        t3.start();

    }
}

3、BankVersion2

public class BankVersion2 {

    public static void main(String[] args) {

        final TicketWindowRunnable ticketWindow = new TicketWindowRunnable();

        Thread windowThread1 = new Thread(ticketWindow, "一号窗口");
        Thread windowThread2 = new Thread(ticketWindow, "二号窗口");
        Thread windowThread3 = new Thread(ticketWindow, "三号窗口");
        windowThread1.start();
        windowThread2.start();
        windowThread3.start();
    }
}
public class TicketWindowRunnable implements Runnable {

    private final static Integer MAX = 500;

    private Integer index = 1;

    private final Object MONITOR = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (MONITOR) {
                if (index > MAX)
                    break;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + " 的号码为:" + index++);
            }

        }
    }
}

4、BankVersion3

public class BankVersion3 {
    public static void main(String[] args) {
        final SynchronizedRunnable ticketWindow = new SynchronizedRunnable();

        Thread windowThread1 = new Thread(ticketWindow, "一号窗口");
        Thread windowThread2 = new Thread(ticketWindow, "二号窗口");
        Thread windowThread3 = new Thread(ticketWindow, "三号窗口");
        windowThread1.start();
        windowThread2.start();
        windowThread3.start();
    }
}
public class SynchronizedRunnable implements Runnable {
    private int index = 1;
    //只读共享数据
    private final static int MAX = 500;

    //this
    @Override
    public void run() {
        while (true) {
            if (ticket()) {
                break;
            }
        }
    }

    //    private synchronized boolean ticket() {
//        if (index>MAX){
//            return true;
//        }
//        try {
//            Thread.sleep(5);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        System.out.println(Thread.currentThread() + " 的号码是:" + (index++));
//        return false;
//    }
    private boolean ticket() {
        synchronized (this) {

            if (index > MAX) {
                return true;
            }
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread() + " 的号码是:" + (index++));
            return false;
        }
    }
}

5、//静态同步代码块

public class SychronizedStaticTest {
    public static void main(String[] args) {
        new Thread("T1") {
            @Override
            public void run() {
                SynchronizedStatic.m1();
            }
        }.start();

        new Thread("T2") {
            @Override
            public void run() {
                SynchronizedStatic.m2();
            }
        }.start();

        new Thread("T3") {
            @Override
            public void run() {
                SynchronizedStatic.m3();
            }
        }.start();
    }
}

public class SynchronizedStatic {
    static {
        synchronized (SynchronizedStatic.class) {
            try {
                System.out.println("static " + Thread.currentThread().getName());
                Thread.sleep(10_000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized static void m1() {
        System.out.println("m1 " + Thread.currentThread().getName());
        try {
            Thread.sleep(10_000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized static void m2() {
        System.out.println("m2 " + Thread.currentThread().getName());
        try {
            Thread.sleep(10_000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void m3() {
        System.out.println("m3 " + Thread.currentThread().getName());
        try {
            Thread.sleep(10_000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
输出
static T1
m1 T1
m3 T3
m2 T2
**/

例子10-deadLock

/**
死锁例子
查看方式:jps
 jstack 端口
 */
public class DeadLockExample {
    public static void main(String[] args) {
        deadLock();
    }

    private static void deadLock() {
        final Object OBJ1 = new Object();
        final Object OBJ2 = new Object();
        new Thread(() -> {
            synchronized (OBJ1) {
                System.out.println("获取obj1成功");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (OBJ2) {
                    System.out.println("获取obj2成功");
                }
            }
        }).start();

        new Thread(() -> {
            synchronized (OBJ2) {
                System.out.println("获取obj2成功");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (OBJ1) {
                    System.out.println("获取obj1成功");
                }
            }
        }).start();
    }

}

//自定义deadLock
public class OtherService {
    private final Object lock = new Object();
    private DeadLock deadLock;
    public void s1() {
        synchronized (lock){
            System.out.println("s1========");
        }
    }
    public void s2(){
        synchronized (lock){
            System.out.println("s2====");
            deadLock.m2();
        }
    }

    public void setDeadLock(DeadLock deadLock) {
        this.deadLock = deadLock;
    }
}
public class DeadLock {
    private OtherService otherService;

    public DeadLock(OtherService otherService) {
        this.otherService = otherService;
    }

    private final Object lock = new Object();

    public void m1() {
        synchronized (lock) {
            System.out.println("m1");
            otherService.s1();
        }
    }

    public void m2() {
        synchronized (lock) {
            System.out.println("m2");
        }
    }
}


public class DeadLockTest {
    public static void main(String[] args) {
        OtherService otherService = new OtherService();
        DeadLock deadLock = new DeadLock(otherService);
        otherService.setDeadLock(deadLock);
        new Thread(() -> {
            while (true) {
                deadLock.m1();
            }
        }).start();

        new Thread(() -> {
            while (true)
                otherService.s2();
        }).start();
    }
}

例子11

/**
 * 采集sevice
 * 同时工作的线程不超过5个
 */
public class CaptureService {
    private final static LinkedList<Control> CONTROLS = new LinkedList();
    private final static Integer MAX_WORKER = 5;

    public static void main(String[] args) {
        List<Thread> worker = new ArrayList<>();
        Arrays.asList("M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9", "M10").stream()
                .map(CaptureService::createCaptureThread).forEach(
                        t->{
                            t.start();
                            worker.add(t);
                        }
        );
        worker.stream().forEach(
                t->{
                    try {
                        t.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
        );
        Optional.of("All of capture work finished").ifPresent(System.out::println);
    }

    private static Thread createCaptureThread(String name) {
        return new Thread(()->{
            Optional.of("The worker [" + Thread.currentThread().getName() + "] BEGIN capture data.")
                    .ifPresent(System.out::println);
            synchronized (CONTROLS){
                while (CONTROLS.size()>MAX_WORKER){
                    try {
                        CONTROLS.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                CONTROLS.addLast(new Control());;
            }
            Optional.of("The worker [" + Thread.currentThread().getName() + "] is working...")
                    .ifPresent(System.out::println);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (CONTROLS){
                Optional.of("The worker [" + Thread.currentThread().getName() + "] END capture data.")
                        .ifPresent(System.out::println);
                CONTROLS.removeFirst();
                CONTROLS.notifyAll();
            }
        },name);
    }

}
class Control{

}

wait和sleep的不同

public class DifferenceOfWaitAndSleep {

    private final static Object LOCK = new Object();

    public static void main(String[] args) {
        Stream.of("T1", "T2").forEach(name ->
                new Thread(name) {
                    @Override
                    public void run() {
                        m2();
                    }
                }.start()
        );
    }

    public static void m1() {
        synchronized (LOCK) {
            try {
                System.out.println("The Thread " + Thread.currentThread().getName() + " enter.");
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    public static void m2() {
        synchronized (LOCK) {
            try {
                System.out.println("The Thread " + Thread.currentThread().getName() + " enter.");
                LOCK.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

生产者消费者问题1(生产完没告诉我,也不知道是不是最新的)

public class ProduceConsumerVersion1 {
    private int i = 1;

    final private Object LOCK = new Object();

    private void produce() {
        synchronized (LOCK) {
            System.out.println("P->" + (i++));
        }
    }

    private void consume() {
        synchronized (LOCK) {
            System.out.println("C->" + i);
        }
    }

    public static void main(String[] args) {

        ProduceConsumerVersion1 pc = new ProduceConsumerVersion1();

        new Thread("P") {
            @Override
            public void run() {
                while (true)
                    pc.produce();
            }
        }.start();

        new Thread("C") {
            @Override
            public void run() {
                while (true)
                    pc.consume();
            }
        }.start();
    }
}

生产者消费者2(多线程下有问题)假死:都放弃了CP执行权 wait了

public class ProduceConsumerVersion2 {
    private int i = 0;

    private final Object LOCK = new Object();

    private volatile boolean isProduce = false;

    public void produce() {
        synchronized (LOCK){
            if (isProduce){
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                i++;
                System.out.println("P->"+i);
                LOCK.notify();
                isProduce = true;
            }
        }
    }
    public void consume(){
        synchronized (LOCK){
            if (isProduce){
                System.out.println("C->"+i);
                LOCK.notify();
                isProduce = false;
            }else{
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        ProduceConsumerVersion2 pc = new ProduceConsumerVersion2();
        Stream.of("P1","P2").forEach(
                n-> new Thread(n){
                    @Override
                    public void run() {
                        while (true)
                            pc.produce();
                    }
                }.start()
        );
        Stream.of("C1","C2").forEach(
                n-> new Thread(n){
                    @Override
                    public void run() {
                        while (true)
                            pc.consume();
                    }
                }.start()
        );
    }
}

生产者消费者3 (多线程完整版)

//
public class ProduceConsumerVersion3 {
    private int i = 0;

    private final Object LOCK = new Object();

    private volatile boolean isProduce = false;

    public void produce() {
        synchronized (LOCK) {
            while (isProduce) {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            i++;
            System.out.println("P->" + i);
            LOCK.notifyAll();
            isProduce = true;

        }
    }

    public void consume() {
        synchronized (LOCK) {
            while (!isProduce) {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            System.out.println("C->" + i);
            LOCK.notify();
            isProduce = false;

        }
    }

    public static void main(String[] args) {
        ProduceConsumerVersion3 pc = new ProduceConsumerVersion3();
        Stream.of("P1", "P2").forEach(
                n -> new Thread(n) {
                    @Override
                    public void run() {
                        while (true) {
                            pc.produce();
                            try {
                                Thread.sleep(1);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start()
        );
        Stream.of("C1", "C2").forEach(
                n -> new Thread(n) {
                    @Override
                    public void run() {
                        while (true){
                            pc.consume();
                            try {
                                Thread.sleep(1);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start()
        );
    }
}

sleep()和wait()的区别:
1.sleep()是Thread()的方法,而wait()是Object()的方法
2.sleep()不会释放Object的监控,而wait()会释放监控并把Object monitor加到队列中
3.sleep()不依赖monitor,而wait()需要
4.sleep()不需要wakeup,而wait()需要

例子12-自定义lock锁

public interface Lock {
    class TimeOutException extends Exception {
        public TimeOutException(String message) {
            super(message);
        }
    }

    void lock() throws InterruptedException;

    void lock(long mills) throws InterruptedException, TimeOutException;

    void unlock();

    Collection<Thread> getBlockedThread();

    int getBlockedSize();
}

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

public class BooleanLock implements Lock {

    private boolean initValue;
    private Collection<Thread> blockedThreadCollection = new ArrayList<>();
    private Thread currentThread;

    public BooleanLock() {
        this.initValue = false;
    }

    @Override
    public synchronized void lock() throws InterruptedException {
        while (initValue){
            blockedThreadCollection.add(Thread.currentThread());
            this.wait();
        }
        blockedThreadCollection.remove(Thread.currentThread());
        this.initValue = true;
        this.currentThread = Thread.currentThread();
    }

    @Override
    public synchronized void lock(long mills) throws InterruptedException, TimeOutException {
        if (mills <=0){
            lock();
        }
        long hasRemaining = mills;
        long endTime = System.currentTimeMillis() + mills;
        while (initValue){
            if (hasRemaining<=0){
                throw new TimeOutException("Time Out");
            }
            blockedThreadCollection.add(Thread.currentThread());
            this.wait(mills);
            hasRemaining= endTime - System.currentTimeMillis();
        }
        this.initValue = true;
        this.currentThread = Thread.currentThread();
    }

    @Override
    public synchronized void unlock() {
        if (Thread.currentThread() == currentThread){
            this.initValue = false;
            Optional.of(Thread.currentThread().getName() + " release the lock monitor.")
                    .ifPresent(System.out::println);
            this.notifyAll();
        }
    }

    @Override
    public Collection<Thread> getBlockedThread() {
        return Collections.unmodifiableCollection(blockedThreadCollection);
    }

    @Override
    public int getBlockedSize() {
        return blockedThreadCollection.size();
    }
}
import java.util.Optional;
import java.util.stream.Stream;

public class LockTest {
    public static void main(String[] args) throws InterruptedException {

        final BooleanLock booleanLock = new BooleanLock();
        Stream.of("T1", "T2", "T3", "T4")
                .forEach(name ->
                        new Thread(() -> {
                            try {
                                booleanLock.lock(100L);
                                Optional.of(Thread.currentThread().getName() + " have the lock Monitor")
                                        .ifPresent(System.out::println);
                                work();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } catch (Lock.TimeOutException e) {
                                Optional.of(Thread.currentThread().getName() + " time out")
                                        .ifPresent(System.out::println);
                            } finally {
                                booleanLock.unlock();
                            }
                        }, name).start()
                );
    }

    private static void work() throws InterruptedException {
        Optional.of(Thread.currentThread().getName() + " is Working...")
                .ifPresent(System.out::println);
        Thread.sleep(4_000);
    }
}

例子13 -线程发生异常怎么捕获

//Thread对发生异常的捕获
public class ThreadException {
    private final static int A = 10;
    private final static int B = 0;


    public static void main(String[] args) {

//        new Test1().test();

        Thread t = new Thread(() -> {
            try {
                Thread.sleep(5_000L);
                int result = A / B;
                System.out.println(result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t.setUncaughtExceptionHandler((thread, e) -> {
            System.out.println(e);
            System.out.println(thread);
        });

        t.start();
    }
}

public class Test1
{

    private Test2 test2 = new Test2();

    public void test(){
        test2.test();
    }
}

public class Test2 {

    public void test() {
        Arrays.asList(Thread.currentThread().getStackTrace()).stream()
                .filter(e->!e.isNativeMethod())
                .forEach(e-> Optional.of(e.getClassName()+":"+e.getMethodName()+":"+e.getLineNumber())
                .ifPresent(System.out::println));
    }
}

例子14-ThreadGroup

创建ThreadGroup

public class ThreadGroupCreate {

    public static void main(String[] args) {
        //use the name

        ThreadGroup tg1 = new ThreadGroup("TG1");
        Thread t1 = new Thread(tg1, "t1") {
            @Override
            public void run() {
                while (true) {
                    try {
                        System.out.println(getThreadGroup().getName());//TG1
                        System.out.println(getThreadGroup().getParent());//java.lang.ThreadGroup[name=main,maxpri=10]
                        System.out.println(getThreadGroup().getParent().activeCount());//3
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        t1.start();

        System.out.println("===============");
        ThreadGroup tg2 = new ThreadGroup("TG2");
        Thread t2 = new Thread(tg2, "T2") {
            @Override
            public void run() {
                System.out.println(">>>"+tg1.getName());//>>>TG1
                Thread[] threads = new Thread[tg1.activeCount()];
                tg1.enumerate(threads);
                System.out.println("+++");
                Arrays.asList(threads).forEach(System.out::println);//Thread[t1,5,TG1]
            }
        };

        t2.start();

        System.out.println(tg2.getName());//TG2
        System.out.println(tg2.getParent());//java.lang.ThreadGroup[name=main,maxpri=10]


        System.out.println(Thread.currentThread().getName());//main
        System.out.println(Thread.currentThread().getThreadGroup().getName());//main
    }
}

ThreadAPI

public class ThreadGroupAPI {
    public static void main(String[] args) throws InterruptedException {

        ThreadGroup tg1 = new ThreadGroup("TG1");
        Thread t1 = new Thread(tg1, "t1") {
            @Override
            public void run() {
                while (true) {
                try {
                    Thread.sleep(1_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
                }
            }
        };

//        tg1.setDaemon(true);
        t1.start();
//        Thread.sleep(2_000);
//        System.out.println(tg1.isDestroyed());
//        tg1.destroy();
//        System.out.println(tg1.isDestroyed());
//
        ThreadGroup tg2 = new ThreadGroup(tg1, "TG2");
        Thread t2 = new Thread(tg2, "T2") {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }
        };

        t2.start();

        System.out.println(tg1.activeCount());
        System.out.println(tg1.activeGroupCount());
        t2.checkAccess();
//        tg1.destroy();

        System.out.println("=========================");
        Thread[] ts1 = new Thread[tg1.activeCount()];
        tg1.enumerate(ts1);
        Arrays.asList(ts1).forEach(System.out::println);

        System.out.println("=========================");
        tg1.enumerate(ts1, true);
        Arrays.asList(ts1).forEach(System.out::println);

        System.out.println("=========================");
        ts1 = new Thread[10];
        Thread.currentThread().getThreadGroup().enumerate(ts1, false);
        Arrays.asList(ts1).forEach(System.out::println);

        tg1.interrupt();

    }
}

简单的线程池

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class SimpleThreadPool extends Thread {

    private int size;

    private final int queueSize;

    private final static int DEFAULT_TASK_QUEUE_SIZE = 2000;

    private static volatile int seq = 0;

    private final static String THREAD_PREFIX = "SIMPLE_THREAD_POOL-";

    private final static ThreadGroup GROUP = new ThreadGroup("Pool_Group");

    private final static LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();

    private final static List<WorkerTask> THREAD_QUEUE = new ArrayList<>();

    private final DiscardPolicy discardPolicy;

    public final static DiscardPolicy DEFAULT_DISCARD_POLICY = () -> {
        throw new DiscardException("Discard This Task.");
    };

    private volatile boolean destroy = false;

    private int min;

    private int max;

    private int active;

    public SimpleThreadPool() {
        this(4, 8, 12, DEFAULT_TASK_QUEUE_SIZE, DEFAULT_DISCARD_POLICY);
    }

    public SimpleThreadPool(int min, int active, int max, int queueSize, DiscardPolicy discardPolicy) {
        this.min = min;
        this.active = active;
        this.max = max;
        this.queueSize = queueSize;
        this.discardPolicy = discardPolicy;
        init();
    }

    private void init() {
        for (int i = 0; i < this.min; i++) {
            createWorkTask();
        }
        this.size = min;
        this.start();
    }

    public void submit(Runnable runnable) {
        if (destroy)
            throw new IllegalStateException("The thread pool already destroy and not allow submit task.");

        synchronized (TASK_QUEUE) {
            if (TASK_QUEUE.size() > queueSize)
                discardPolicy.discard();
            TASK_QUEUE.addLast(runnable);
            TASK_QUEUE.notifyAll();
        }
    }

    @Override
    public void run() {
        while (!destroy) {
            System.out.printf("Pool#Min:%d,Active:%d,Max:%d,Current:%d,QueueSize:%d\n",
                    this.min, this.active, this.max, this.size, TASK_QUEUE.size());
            try {
                Thread.sleep(5_000L);
                if (TASK_QUEUE.size() > active && size < active) {
                    for (int i = size; i < active; i++) {
                        createWorkTask();
                    }
                    System.out.println("The pool incremented to active.");
                    size = active;
                } else if (TASK_QUEUE.size() > max && size < max) {
                    for (int i = size; i < max; i++) {
                        createWorkTask();
                    }
                    System.out.println("The pool incremented to max.");
                    size = max;
                }

                synchronized (THREAD_QUEUE) {
                    if (TASK_QUEUE.isEmpty() && size > active) {
                        System.out.println("=========Reduce========");
                        int releaseSize = size - active;
                        for (Iterator<WorkerTask> it = THREAD_QUEUE.iterator(); it.hasNext(); ) {
                            if (releaseSize <= 0)
                                break;

                            WorkerTask task = it.next();
                            task.close();
                            task.interrupt();
                            it.remove();
                            releaseSize--;
                        }
                        size = active;
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void createWorkTask() {
        WorkerTask task = new WorkerTask(GROUP, THREAD_PREFIX + (seq++));
        task.start();
        THREAD_QUEUE.add(task);
    }

    public void shutdown() throws InterruptedException {
        while (!TASK_QUEUE.isEmpty()) {
            Thread.sleep(50);
        }

        synchronized (THREAD_QUEUE) {
            int initVal = THREAD_QUEUE.size();
            while (initVal > 0) {
                for (WorkerTask task : THREAD_QUEUE) {
                    if (task.getTaskState() == TaskState.BLOCKED) {
                        task.interrupt();
                        task.close();
                        initVal--;
                    } else {
                        Thread.sleep(10);
                    }
                }
            }
        }

        System.out.println(GROUP.activeCount());

        this.destroy = true;
        System.out.println("The thread pool disposed.");
    }

    public int getQueueSize() {
        return queueSize;
    }

    public int getSize() {
        return size;
    }

    public boolean isDestroy() {
        return this.destroy;
    }

    public int getMin() {
        return min;
    }

    public int getMax() {
        return max;
    }

    public int getActive() {
        return active;
    }

    private enum TaskState {
        FREE, RUNNING, BLOCKED, DEAD
    }

    public static class DiscardException extends RuntimeException {

        public DiscardException(String message) {
            super(message);
        }
    }

    public interface DiscardPolicy {

        void discard() throws DiscardException;
    }

    private static class WorkerTask extends Thread {

        private volatile TaskState taskState = TaskState.FREE;

        public WorkerTask(ThreadGroup group, String name) {
            super(group, name);
        }

        public TaskState getTaskState() {
            return this.taskState;
        }

        public void run() {
            OUTER:
            while (this.taskState != TaskState.DEAD) {
                Runnable runnable;
                synchronized (TASK_QUEUE) {
                    while (TASK_QUEUE.isEmpty()) {
                        try {
                            taskState = TaskState.BLOCKED;
                            TASK_QUEUE.wait();
                        } catch (InterruptedException e) {
                            System.out.println("Closed.");
                            break OUTER;
                        }
                    }
                    runnable = TASK_QUEUE.removeFirst();
                }

                if (runnable != null) {
                    taskState = TaskState.RUNNING;
                    runnable.run();
                    taskState = TaskState.FREE;
                }
            }
        }

        public void close() {
            this.taskState = TaskState.DEAD;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SimpleThreadPool threadPool = new SimpleThreadPool();
        for (int i = 0; i < 40; i++) {
            threadPool.submit(() -> {
                System.out.println("The runnable  be serviced by " + Thread.currentThread() + " start.");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("The runnable be serviced by " + Thread.currentThread() + " finished.");
            });
        }

        Thread.sleep(10000);
        threadPool.shutdown();

       /* Thread.sleep(10000);
        threadPool.shutdown();
        threadPool.submit(() -> System.out.println("======="));*/
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值