ソースを参照

0717 线程巩固和进阶

Qing 10 ヶ月 前
コミット
8c018ab5b9

+ 81 - 0
springboot-demo/src/main/java/com/sf/javase/thread/commu/TestNotify.java

@@ -0,0 +1,81 @@
+package com.sf.javase.thread.commu;
+
+import lombok.SneakyThrows;
+
+import java.util.ArrayList;
+import java.util.List;
+
+// 模拟一个线程通信的场景
+// 首先要有两个线程 一个线程需要在另一个线程要求的某个条件下触发它
+// 一个线程在未满足条件时 要wait  另一个线程在满足了刚才的条件后 要notify
+public class TestNotify {
+
+    @SneakyThrows
+    public static void main(String[] args) {
+        // 创建一个list对象 代替Mylist
+        List<Integer> list = new ArrayList();
+        // 第一个线程需要等待
+        ThreadA threadA = new ThreadA(list);
+        threadA.start();
+        // 确保ThreadA先执行
+        Thread.sleep(100);
+
+        // 第二个线程需要触发唤醒
+        ThreadB threadB = new ThreadB(list);
+        threadB.start();
+    }
+
+}
+
+// MyList 提供一个多线程共享的容器
+
+class ThreadA extends Thread {
+    // 替换了原来的Object
+    private List list;
+
+    public ThreadA(List list) {
+        this.list = list;
+    }
+
+    @Override
+    public void run() {
+        synchronized (list) {
+            if (list.size() < 3) {
+                try {
+                    System.out.println("wait begin");
+                    list.wait();
+                    System.out.println("wait end");
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+}
+
+class ThreadB extends Thread {
+    private List list;
+
+    public ThreadB(List list) {
+        this.list = list;
+    }
+
+    // Sneaky 暗中的 处理异常
+    @SneakyThrows
+    @Override
+    public void run() {
+        for (int i = 0; i < 6; i++) {
+            list.add(i);
+            System.out.println("add " + i);
+            // 尽量缩小锁的粒度
+            // 如果满足另一线程等待的条件 可以发起通知
+            synchronized (list) {
+                if (list.size() == 3) {
+                    list.notify();
+                    System.out.println("notify start");
+                }
+            }
+            Thread.sleep(1000);
+        }
+    }
+}

+ 35 - 0
springboot-demo/src/main/java/com/sf/javase/thread/commu/TestNotify1.java

@@ -0,0 +1,35 @@
+package com.sf.javase.thread.commu;
+
+import lombok.SneakyThrows;
+
+public class TestNotify1 {
+
+    public static void main(String[] args) {
+        MyCommunication myCommunication = new MyCommunication();
+        new Thread(myCommunication, "A").start();
+        new Thread(myCommunication, "B").start();
+        new Thread(myCommunication, "C").start();
+    }
+}
+
+// 使用同一个Runnable来进行线程通信
+class MyCommunication implements Runnable {
+    // 初始变量
+    int num = 0;
+
+    @SneakyThrows
+    @Override
+    public void run() {
+        while (true) {
+            synchronized (this) {
+                this.notifyAll();
+                // 设置num递增的最大值
+                if (num >= 100) break;
+                // 希望三个线程切换着对变量num递增
+                System.out.println(Thread.currentThread().getName() + ": " + num++);
+                // 当前线程处理完切换给其他线程
+                this.wait();
+            }
+        }
+    }
+}

+ 33 - 0
springboot-demo/src/main/java/com/sf/javase/thread/control/TestJoin.java

@@ -0,0 +1,33 @@
+package com.sf.javase.thread.control;
+
+public class TestJoin extends Thread {
+
+    public TestJoin(String name){
+        super(name);
+    }
+
+    @Override
+    public void run() {
+        for (int i = 0; i < 50; i++) {
+            System.out.println(getName() + " " + i);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        // 设置线程的名字
+        new TestJoin("Thread11").start();
+        for (int i = 0; i < 50; i++) {
+
+            if (i == 20) {
+                TestJoin thread22 = new TestJoin("Thread22");
+                thread22.start();
+                // main的主线程中调用了 thread22线程的join()方法
+                // 需要等待此线程结束后才能继续执行
+                thread22.join();
+            }
+
+            System.out.println(Thread.currentThread().getName()
+                    + " " + i);
+        }
+    }
+}

+ 33 - 0
springboot-demo/src/main/java/com/sf/javase/thread/control/TestOrder.java

@@ -0,0 +1,33 @@
+package com.sf.javase.thread.control;
+
+public class TestOrder {
+
+    public static void main(String[] args) throws InterruptedException {
+        Thread t1 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                System.out.println("1");
+
+            }
+        });
+        Thread t2 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                System.out.println("2");
+
+            }
+        });
+        Thread t3 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                System.out.println("3");
+
+            }
+        });
+        t1.start();
+        t1.join();
+        t2.start();
+        t2.join();
+        t3.start();
+    }
+}

+ 58 - 0
springboot-demo/src/main/java/com/sf/javase/thread/control/TestShunXun.java

@@ -0,0 +1,58 @@
+package com.sf.javase.thread.control;
+
+public class TestShunXun {
+
+    public static void main(String[] args) {
+        T1 t1 = new T1();
+        T2 t2 = new T2(t1);
+        T3 t3 = new T3(t2);
+        t1.start();
+        t2.start();
+        t3.start();
+    }
+}
+
+class T1 extends Thread {
+    @Override
+    public void run() {
+        System.out.println("1");
+    }
+
+}
+
+class T2 extends Thread {
+    private T1 t1;
+
+    public T2(T1 t1) {
+        this.t1 = t1;
+    }
+
+    @Override
+    public void run() {
+        try {
+            t1.join();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        System.out.println("2");
+    }
+
+}
+
+class T3 extends Thread {
+    private T2 t2;
+
+    public T3(T2 t2) {
+        this.t2 = t2;
+    }
+
+    @Override
+    public void run() {
+        try {
+            t2.join();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        System.out.println("3");
+    }
+}

+ 35 - 0
springboot-demo/src/main/java/com/sf/javase/thread/sync/SyncMain.java

@@ -0,0 +1,35 @@
+package com.sf.javase.thread.sync;
+
+// 线程安全问题 因为执行的不确定性导致结果的不稳定性
+// sync加锁 同步代码块 同步方法
+// Lock加锁
+public class SyncMain {
+
+    // 类的静态变量只有一个
+    static int num = 0;
+
+    // 线程共享资源会出现的问题
+    // 创建两个线程 对同一个资源变量i 做自增和自减
+    public static void main(String[] args) throws InterruptedException {
+        // lambda表达式 本质上是不关心类和方法名是什么
+        // 只关心方法的入参和方法体的逻辑  只关心代码逻辑
+        Thread t1 = new Thread(() -> {
+            for (int i = 0; i < 5000; i++) {
+                num++;
+            }
+            System.out.println(num);
+        });
+        Thread t2 = new Thread(() -> {
+            for (int i = 0; i < 5000; i++) {
+                num--;
+            }
+            System.out.println(num);
+        });
+
+        t1.start();
+        t2.start();
+//        t1.join();
+//        t2.join();
+//        System.out.println(num);
+    }
+}

+ 39 - 0
springboot-demo/src/main/java/com/sf/javase/thread/sync/Ticket.java

@@ -0,0 +1,39 @@
+package com.sf.javase.thread.sync;
+
+import lombok.SneakyThrows;
+
+// 解决买票的超卖问题
+public class Ticket {
+
+    public static void main(String[] args) {
+        Window window = new Window();
+        // 三个线程使用同一个window对象
+        // 一个window对象 只有一个lock对象 所以使用的是同一把锁
+        new Thread(window, "t1").start();
+        new Thread(window, "t2").start();
+        new Thread(window, "t3").start();
+    }
+
+    private static class Window implements Runnable {
+
+        private int ticketsNum = 100;
+        // 创建一个对象 用对象来加锁
+        Object lock = new Object();
+
+        // lombok提供了一个处理异常的注解
+        @SneakyThrows
+        @Override
+        public void run() {
+            while (true) {
+                // 同步代码块
+                synchronized (lock) {
+                    if (ticketsNum > 0) {
+                        Thread.sleep(100);
+                        System.out.println(Thread.currentThread().getName() + " : " + ticketsNum--);
+                    }
+                }
+            }
+        }
+    }
+}
+

+ 40 - 0
springboot-demo/src/main/java/com/sf/javase/thread/sync/TicketAtomic.java

@@ -0,0 +1,40 @@
+package com.sf.javase.thread.sync;
+
+import lombok.SneakyThrows;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+// 解决买票的超卖问题
+public class TicketAtomic {
+
+    public static void main(String[] args) {
+        Window window = new Window();
+        // 三个线程使用同一个window对象
+        // 一个window对象 只有一个lock对象 所以使用的是同一把锁
+        new Thread(window, "t1").start();
+        new Thread(window, "t2").start();
+        new Thread(window, "t3").start();
+    }
+
+    private static class Window implements Runnable {
+
+        // 修改票数的类型 为原子的整数类
+        private AtomicInteger ticketsNum = new AtomicInteger(100);
+
+        // lombok提供了一个处理异常的注解
+        @SneakyThrows
+        @Override
+        public void run() {
+            while (true) {
+                // AtomicInteger 通过get()方法来获取数值
+                if (ticketsNum.get() > 0) {
+                    Thread.sleep(100);
+                    // 使用getAndDecrement来进行自减
+                    System.out.println(Thread.currentThread().getName() + " : " + ticketsNum.getAndDecrement());
+                }
+
+            }
+        }
+    }
+}
+

+ 42 - 0
springboot-demo/src/main/java/com/sf/javase/thread/sync/TicketLock.java

@@ -0,0 +1,42 @@
+package com.sf.javase.thread.sync;
+
+import lombok.SneakyThrows;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+// 解决买票的超卖问题
+public class TicketLock {
+
+    public static void main(String[] args) {
+        Window window = new Window();
+        // 三个线程使用同一个window对象
+        // 一个window对象 只有一个lock对象 所以使用的是同一把锁
+        new Thread(window, "t1").start();
+        new Thread(window, "t2").start();
+        new Thread(window, "t3").start();
+    }
+
+    private static class Window implements Runnable {
+
+        private int ticketsNum = 100;
+        // 创建一个可重入锁的对象
+        ReentrantLock lock = new ReentrantLock();
+
+        // lombok提供了一个处理异常的注解
+        @SneakyThrows
+        @Override
+        public void run() {
+            while (true) {
+                // 加锁
+                lock.lock();
+                if (ticketsNum > 0) {
+                    Thread.sleep(100);
+                    System.out.println(Thread.currentThread().getName() + " : " + ticketsNum--);
+                }
+                // 释放锁
+                lock.unlock();
+            }
+        }
+    }
+}
+

+ 42 - 0
springboot-demo/src/main/java/com/sf/javase/thread/sync/TicketSyncMethod.java

@@ -0,0 +1,42 @@
+package com.sf.javase.thread.sync;
+
+import lombok.SneakyThrows;
+
+// 解决买票的超卖问题
+public class TicketSyncMethod {
+
+    public static void main(String[] args) {
+        Window window = new Window();
+        // 三个线程使用同一个window对象
+        // 一个window对象 只有一个lock对象 所以使用的是同一把锁
+        new Thread(window, "t1").start();
+        new Thread(window, "t2").start();
+        new Thread(window, "t3").start();
+    }
+
+    // 静态内部类
+    private static class Window implements Runnable {
+
+        private int ticketsNum = 100;
+
+        @Override
+        public void run() {
+            while (true) {
+               sale();
+            }
+        }
+
+        // 使用同步方法来加锁
+        // 此时同步方法使用的锁 就是当前对象 synchronized(this){}
+        // 如果使用静态同步方法 此时的锁是当前类 synchronized(Window.class){}
+        // lombok提供了一个处理异常的注解
+        @SneakyThrows
+        private synchronized void sale(){
+            if (ticketsNum > 0) {
+                Thread.sleep(100);
+                System.out.println(Thread.currentThread().getName() + " : " + ticketsNum--);
+            }
+        }
+    }
+}
+