汪文君->多线程教程

汪文君-多线程教程

第一阶段

多线程介绍
多线程编程入门
多线程创建与启动以及线程状态
Runnable接口详细详解
线程优先级以及守护线程详解
线程同步
线程间通讯
线程组详解
自运行对象详解
线程异常回调
线程池详解
等待线程完成任务
阻塞io和多线程详解
如何优雅的结束线程
自定义线程锁详解
fifo队列与线程
多线程api查缺补漏

第二阶段

waitset概念介绍
多线程程序很亮标准
single thread execution模式
不可变对象以及线程安全对象
guraded suspension模式
balking模式介绍
producer-consumer介绍
读写锁设计模式介绍
thread-pre-message模式
worker模式
future设计模式介绍
two-phase termination设计模式
thread-specific stoage模式
avtive object 接收异步消息的主动对象
设计模式差缺补漏

第三阶段

原子变量
unsafe
countdownlatch
cyclicbarrier
exchanger
phaser
显式锁-reetrantlock
显式锁-readwritelock
显式锁-stampedlock
condition
semaphore信号量
forkjoin框架
concurrenthashmap
concurrentlinkeddeque
cuncurrentskiplistmap
concurrentskipset
copyonwriteArrayList
CopyOnWriteArraySet
DelayQueue
LinkedBlockingBqueue
PriorityBlockingQueue
CompletableFuture
自定义ThreadPoolExector
实现一个优先级线程池

第四阶段

死锁诊断,jvm工具,线程堆栈介绍
线程安全性讨论
数据共享,以及数据共享带来安全隐患
构建线程安全的类,选择优化策略
构建并行模块
构建并行任务介绍
任务执行与关闭
线程池优化
线程上下文,性能,可伸缩性讨论
构建同步工具
原子变量与非阻塞同步机制
google concurrent包接搜啊
google eventBus包介绍
java应用main函数是一个线程被jvm启动时候调用的,线程名称是main,实现一个线程必须创建thread实例, 实现run方法,调用start方法,jvm启动后,实际有多个线程,至少有一个非守护线程,当调用一个线程start方法,至少两个线程,一个是调用线程一个是守护线程。

线程生命周期,new,runnable,running,block,termate。

多线程叫号的应用

1到50用三个线程叫号,一个基础版本,解决三个叫号问题。

public class TicketWindow  extends  Thread{
    private  static int MAX=50;
    private static int INDEX=1;
        private String name;

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

    @Override
    public void run() {
       while (INDEX<=MAX){

           System.out.println(name+   INDEX++ );
       }
    }

    public static void main(String[] args) {
        TicketWindow t1 = new TicketWindow("一号机器");
        t1.start();

        TicketWindow t2 = new TicketWindow("二号机器");
        t2.start();

        TicketWindow t3 = new TicketWindow("三号机器");
        t3.start();
    }

想让三个柜台顺序执行如何操作呢?

提取专门计算税率的接口。

CalculatorStrategy 计算税率接口,有默认实现,如果有其他计算规则,使用那个规则就行。

public class TaxCalaculator {
    private double salary;
    private  double bonus;


    private  CalculatorStrategy calculatorStrategy;

    public TaxCalaculator(double salary, double bonus) {
        this.salary = salary;
        this.bonus = bonus;
    }

    protected   double calcTax(CalculatorStrategy calculatorStrategy){
        return  calculatorStrategy.Calculate(salary,bonus);
    }
    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
}

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

  public static void main(String[] args) {
        TaxCalaculator taxCalaculator = new TaxCalaculator(1000d, 500d);
        double v = taxCalaculator.calcTax(new CalculatorStrategyImpl());
        System.out.println(v);

    }

修改版本为:

  public static void main(String[] args) {
        TaxCalaculator taxCalaculator = new TaxCalaculator(1000d, 500d);
        double v = taxCalaculator.calcTax((s,b)->s*0.1+b*0.15);
        System.out.println(v);

    }

还可以改的更简洁一点

直接修改TaxCalaculator 构造器。

   public TaxCalaculator(double salary, double bonus,CalculatorStrategy calculatorStrategy) {
        this.salary = salary;
        this.bonus = bonus;
        this.calculatorStrategy=calculatorStrategy;
    }
  public static void main(String[] args) {
        TaxCalaculator taxCalaculator = new TaxCalaculator(1000d, 500d,(s,b)->s*0.1+b*0.15);
         System.out.println(taxCalaculator.calcTax());

    }

加上java8 的标记

@FunctionalInterface
public interface CalculatorStrategy {
    public   double Calculate(Double salary ,double bonus);
}

用java8的方式运行Runnable

public class Main {
    private  static int MAX=50;
    private static int INDEX=1;
    public static void main(String[] args) {
    Runnable runnable=()->{


        while (INDEX<=MAX){

            System.out.println( Thread.currentThread()+"号码是:"+INDEX++ );
        }
    };

        Thread one = new Thread(runnable, "一号窗口");
        Thread two = new Thread(runnable, "二号窗口");
        Thread three = new Thread(runnable, "三号窗口");
        one.start();
        two.start();
        three.start();

    }
}

thread

默认构造函数,提供默认的线程名称,threadInitNumber++操作,int类型默认值0.

如果在构造thread的时候没有传递runnable或者没有复写thread的run方法,不会调用任何东西。

如果传递了runnable接口的实例,或者复写了thread的run方法,则会执行该方法的逻辑单元。

start是调用了。而 start0()调用的是当前线程类的run方法,如果ThreadGroup没配置就给parent,此时和父线程在同一个ThreadGroup。

  public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
public void run() {
        if (target != null) {
            target.run();
        }
    }
 if (g == null) {
                g = parent.getThreadGroup();
            }

默认有三个后台Thread。

Thread thread = new Thread();

        thread.start();
        thread.getThreadGroup().activeCount();//3
        ThreadGroup threadGroup = thread.getThreadGroup();
        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,]

线程栈是什么东西。

栈里面保存基本类型,引用类型

比如定义了对象,存放引用比如obj 0x00001,具体内容放入堆中

方法区 (存放入口出口,类加载信息,常量变量,静态信息)
虚拟机栈(每个线程私有的)
本地方法区(c++的代码,执行nio的东西,文件的一些东西,jni的东西)
程序计数器(放的指令)
堆内存

jvm做不了许多文章,oom问题可以去解决,每一个你的应用程序达到80,就通过水平扩展的方式,不让他出现异常。跑到60-70就可以的了,做压力测试 在压力上来的时候,
到临界值没必要做样子,不要出现哪有,不要出现生命周期比较长的对象,不要出现死循环,这是对你有帮助的,如果你纠结符号呀,字节码,用处不大。对写程序帮助不是特别大。
还不如了解某个东西原理,了解某个架构。

构造thread的时候传入stacksize代表占用的stack大小,如果没有指定stacksize的大小,默认值是0,0代表着会忽略该参数,该参数会被jni函数去手拍卖行、
需要注意,该参数有一些平台有效,在有些平台则无效。 我们通过命令来操作就是-Xss10M

守护线程和线程的优先级
将线程设置为Daemon(true);之后即使设置为死循环,当main线程结束之后,守护线程也会结束。

只有守护线程的时候会退出,只有在start前掉它会生效。这个线程已经启动了如果再设置为守护线程会抛出异常

public class TicketWindow  extends  Thread{
    private  static int MAX=50;
    private static int INDEX=1;
        private String name;

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

    @Override
    public void run() {
       while (true){

           System.out.println(name+   INDEX++ );
       }
    }

    public static void main(String[] args) throws InterruptedException {
        TicketWindow t1 = new TicketWindow("一号机器");
        t1.setDaemon(true);
        t1.start();
        Thread.sleep(2000);
        System.out.println("死循环结束");

    }
}

用处:建立网络连接的时候,从a到b需要发送心跳包,当前线程创建连接之后需要维护。
开启一个daemon,做心跳检查。如果没有做daemon线程之后。主要活动结束了,这个心跳检查一直不结束不断报错,适合做这个。

如果创建一个主线程,然后在线程里面再创建一个线程这个线程为daemon。这个主线程结束之后它会不会退出呢?(会)如果做非守护线程会不会退出呢?(不会)

public class TicketWindow  extends  Thread{
    private  static int MAX=50;
    private static int INDEX=1;
        private String name;

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

    @Override
    public void run() {
       while (INDEX<=MAX){

           System.out.println(name+   INDEX++ );

           Thread t1 = new Thread() {
               @Override
               public void run() {
                  while (true){
                      System.out.println("我是Daemon");
                  }
               }
           };
          /// t1.setDaemon(true);
           t1.start();
       }
    }

    public static void main(String[] args) throws InterruptedException {
        TicketWindow t1 = new TicketWindow("一号机器");
         t1.start();
    }
}

线程优先级最大是10,最小是1,默认是5.但是分配的优先级不一定能完全控制住线程。

setPriority();
 
    public final static int MIN_PRIORITY = 1;
 
    public final static int NORM_PRIORITY = 5;

   
    public final static int MAX_PRIORITY = 10;

执行1000次,main,使用join之后mian线程会等thread执行完才能执行

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

        Thread thread = new Thread(() -> {
            IntStream.range(1, 1000).forEach(i -> System.out.println(Thread.currentThread().getName()+"--"+i));
        });

        thread.start();
        thread.join();
        IntStream.range(1, 1000).forEach(i -> System.out.println(Thread.currentThread().getName()+"--"+i));
    }

如果线程增加一个,会执行顺序是 t0->t1-main 所以说可以通过join获取到一个任务的完整执行时间且是并发执行。

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


        Thread thread = new Thread(() -> {
            IntStream.range(1, 1000).forEach(i -> System.out.println(Thread.currentThread().getName()+"--"+i));
        });

        thread.start();
        thread.join();


        Thread thread2 = new Thread(() -> {
            IntStream.range(1, 1000).forEach(i -> System.out.println(Thread.currentThread().getName()+"--"+i));
        });

        thread2.start();
        thread2.join();
        IntStream.range(1, 1000).forEach(i -> System.out.println(Thread.currentThread().getName()+"--"+i));
    }

如果两个线程t2 join t1 t1的顺序在t2前面

    public static void main(String[] args) {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("1111111");

            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                try {
                    t1.join();
                    System.out.println("222222222222");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        t1.start();
        t2.start();


    }

线程打断

虽然打断了,成为false,但是程序仍然在运行中。由于没有捕获打断的异常导致。

public class Threadinterrupt {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
             }
        });
        thread.start();
        System.out.println(thread.isInterrupted());
      thread.interrupt();
        System.out.println(thread.isInterrupted());
    }
}

wait,join,sleep 则其中断状态将被清除,并将接收
/**sleep**/
public class Threadinterrupt {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        System.out.println(thread.isInterrupted());
      thread.interrupt();
        System.out.println(thread.isInterrupted());
    }
}

/**wait**/
public class Threadinterrupt {
    private  static final Object MONITOR=new Object();

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
              synchronized (MONITOR){
                  try {
                      MONITOR.wait(10);
                  } catch (InterruptedException e) {
                      throw new RuntimeException(e);
                  }
              }
            }
        });
        thread.start();
        System.out.println(thread.isInterrupted());
      thread.interrupt();
        System.out.println(thread.isInterrupted());
    }
}

t1线程需要其他线程打断它,当我们使用了join之后并没有打断它。

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {

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

                t.interrupt();
                System.out.println("执行了");
            }
        };
        t2.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

t.join(); 其实join的是main线程,所以打断只能打断main线程。

    public static void main(String[] args) {

        Thread main=        Thread.currentThread();
        Thread t = new Thread(() -> {
            while (true) {

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

                main.interrupt();
                System.out.println("执行了");
            }
        };
        t2.start();
        try {
            t.join();
           
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

1.优雅停止,使用开关

public class Worker  extends  Thread{

    private  volatile  Boolean flag=true;
    @Override
    public void run() {
         while (flag){
             System.out.println("运行中..");
         }
        }

    public void halt() {
          flag=false;
    }
}

  public static void main(String[] args) {
        Worker worker = new Worker();
        worker.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        worker.halt();
    }

2.使用打断方式

    public static void main(String[] args) {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (true) {
                    if (Thread.interrupted()) {
                        break;
                    }
                    System.out.println("运行中");
                }
            }
        };

        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        t1.interrupt();
    }

https://www.bilibili.com/video/BV1hJ411D7k2?p=17&spm_id_from=pageDriver&vd_source=d7b34bff85997c3f1b43012976b7d985

优雅的退出,如果任务超时没有完成,可以根据给的默认时间去退出,如果小于任务时间,可以等任务完成后自己结束程序

public class ThreadService {
    private  Thread master;
    private Boolean flag=false;

    public void shutdown(long mills){
        long currentTime=System.currentTimeMillis();
        while (!flag){
            if((System.currentTimeMillis()-currentTime)>=mills){
                System.out.println("任务超时,需要结束");
                master.interrupt();
                break;
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                System.out.println("执行线程被打断");
                break;
            }
        }
        flag=false;
    };
    private long Default_timeout_time=300;

    public void  start(Runnable runnable){
        //创建一个主线程
       master= new Thread(){
            @Override
            public void run() {
                Thread runner = new Thread(runnable);
                runner.setDaemon(true);
                runner.start();
                try {
                    runner.join();
                    flag=true;
                } catch (InterruptedException e) {
                  //  flag=false;

                }

            }
        };

        master.start();

    };

    public static void main(String[] args) {
        ThreadService threadService = new ThreadService();
        long startTime = System.currentTimeMillis();

        threadService.start(new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        threadService.shutdown(10000);
        long endTime = System.currentTimeMillis();
        System.out.println(startTime-endTime);


    }

}

posted @ 2023-08-14 15:49  三号小玩家  阅读(85)  评论(0)    收藏  举报
Title
三号小玩家的 Mail: 17612457115@163.com, 联系QQ: 1359720840 微信: QQ1359720840