JAVA 多线程浅尝

多线程

  • 多线程可以减少业务执行时间,最大化处理器资源利用率

  • 多线程必然涉及到线程不安全,比如抢票,所以就要用到synchronized

  • 线程开启不一定立即执行,由CPU调度执行顺序

  • 创建线程最常用方法如下:

    //实现Runnable接口,重写run()方法
    //创建线程对象,执行线程需要丢入runnable接口实现类,调用start()方法
    public class ThreadTest1 implements Runnable {
        @Override
        public void run() {
            //run方法线程体
            for (int i = 0; i < 20 ; i++) {
                System.out.println("run方法");
            }
        }
        public static void main(String[] args) {
            //创建Runnable接口的实现对象
            ThreadTest1 thread = new ThreadTest1();
            //创建线程对象,通过线程对象来开始我们的线程,代理
            new Thread(thread).start();
            for (int i = 0; i < 20; i++) {
                System.out.println("main方法");
            }
        }
    }
    

  • 龟兔赛跑:

    //龟兔赛跑
    public class ThreadTest3 implements Runnable {
        //胜利者
        private static String winner;
        @Override
        public void run() {
            for (int i = 0; i <= 100; i++) {
                //模拟兔子休息2毫秒
                if (Thread.currentThread().getName().equals("兔子")&& i%10==0){
                    try {
                        Thread.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //判断比赛是否结束
                boolean flag = over(i);
                //如果比赛结束,就停止程序
                if (flag){
                    break;
                }
               System.out.println(Thread.currentThread().getName()+"---->跑了" + i + "步");
            }
        }
        //判断是否完成比赛
        private boolean over(int buShu) {
            //判断是否有胜利者
            if (winner != null) {//已经存在胜利者
                return true;
            }
            if (buShu >= 100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is "+winner);
                return true;
            }
            return false;
        }
        public static void main(String[] args) {
            ThreadTest3 threadTest3 = new ThreadTest3();
            new Thread(threadTest3,"兔子").start();
            new Thread(threadTest3,"乌龟").start();
        }
    
    }
    
    

  • 匿名内部类,没有类名,直接new I接口(),不用像普通别的类一样需要implements接口,然后在new 类的对象,去点方法.

  • lambda表达式:前提是接口为函数式接口(只有一个方法),多个参数

    可以都去掉参数类型,不去掉要加上括号

     定义一个函数式接口
     interface Ilike{
         void lambda(int a);
      }
        
      Ilike love = new Ilike() {
         @Override 匿名内部类
            public void lambda(int a) {
                System.out.println("输出"+a);
           }
       };
      	love.lambda(520);
    
       lambda方式
       Ilike love = a-> System.out.println("我"+a);
       love.lambda(520);
    
    

  • 模拟线程stop

        private boolean flag = true;
        @Override
        public void run() {
            int i = 0;
            while (flag){
                System.out.println("线程执行到->"+i++);
            }
        }
        public void stop(){
            this.flag = false;
        }
        
        public static void main(String[] args) {
            xiancheng xian = new xiancheng();
            new Thread(xian).start();
            for (int i = 0; i < 500; i++) {
                System.out.println("mian->"+i);
                if (i==300){
                    xian.stop();
                    System.out.println("该线程停止了");
                }
            }
        }
    

  • 模拟sleep倒计时,和获取当前时间,(每个对象都有一个锁,sleep不会释放锁)

       public static void main(String[] args) {
            try {
                daoJiShi();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public static void daoJiShi() throws InterruptedException {
            int num = 10;
            while (true){
                Thread.sleep(1000);//1秒的延迟
                System.out.println(num--);
                if (num<0){
                    break;
                }
            }
        }
       
    public class TestSleep {
       public static void main(String[] args) {
             获取系统当前时间
       Date startTime = new Date(System.currentTimeMillis());
            while (true){
                try {
                    Thread.sleep(1000);
                    修改时间格式
        		 System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                    更新当前时间
                    startTime = new Date(System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        
    

  • Join插队

    class JoinTest implements Runnable{
        
        @Override
        public void run() {
            for (int i = 0; i <100; i++) {
                System.out.println("vip线程->"+i);
            }
        }
        public static void main(String[] args) throws InterruptedException {
            JoinTest join = new JoinTest();
            Thread thread = new Thread(join);
            thread.start();
            for (int i = 0; i <100 ; i++) {
                if (i==50){
                    thread.join();//插队
                }
                System.out.println("main"+i);
            }
        }
    }
    

  • Priority线程优先级:

    1. 主线程不能更改,默认5,可设置优先级为1-10
    2. Thread.currentThread().getPriority()主线程默认优先级
    3. 先设置优先级,在启动
    4. 优先级低意味着获得调度的概率低,依然会被调用

  • 守护线程

    1. 线程分为用户线程守护线程

    2. 虚拟机必须确保用户线程执行完毕(就是main())

    3. 虚拟机不用等到守护线程执行完毕

    4. 守护线程如后台记录操作日志,监控内存,垃圾回收

    5. 默认是false用户进程正常线程都是用户线程,true就是守护进程

    6. thread.setDaemon(true)


  • synchronized同步

    1. synchronized修饰符:锁的是this,这个类本身
    2. synchronized(Obj){}同步块:synchronized(变量或this){逻辑代码}
    3. Obj称之为同步监视器
      • Obj可以是任何对象,但是推荐使用变化的量,如增删改的对象
      • 修饰符同步方法中,无需指定同步监视器,因为同步方法的同步监视器就是this就是这个对象本身,或者是class
    //synchronized 线程安全 线程排队购买
    public class Test {
        public static void main(String[] args) {
            BuyPiao mp = new BuyPiao();
            new Thread(mp,"小明").start();
            new Thread(mp,"小红").start();
            new Thread(mp,"小绿").start();
        }
    }
    class BuyPiao implements Runnable{
        //票
        private int piao = 10;
        private boolean flag = true;//外部停止方式
        @Override
        public void run() {
            //买票
            while (true){
                try {
                    buy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public synchronized void buy() throws InterruptedException {
            //判断是否有票
            if (piao<=0){
                flag = false;
                return;
            }
            //模拟延时
            Thread.sleep(100);
            //买到票
            System.out.println(Thread.currentThread().getName()+"买到"+piao--);
        }
    }
    

  • CopyOnWriteArrayList安全类型集合

  • 死锁:多个线程互相持有对方需要的资源,然后形成僵持

在这里插入图片描述
​ 只要两个线程不同时抱一个线程锁就可以了.
在这里插入图片描述

  • Lock是显示锁,只能锁代码块,JVM将花费更少的时间来调度线程,性能更好,扩展性好(有很多子类)
    public void run() {
        while (true){
            try{
                lock.lock();
                if (num>=0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(num--);
                }else {
                    break;
                }
            }finally {
                lock.unlock();
            }

        }

  • 生产者和消费者模式 后厨(生产者)–>吧台(缓冲区)–>顾客(消费者)

    1. wait():表示线程一直等待,知道其他线程通知,与sleep不同,会释放锁

    2. wait(long timeout):指定等待的毫秒数

    3. notify():唤醒一个处于等待状态的线程

    4. notifyAll():唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度

    5. 都是Object类的方法,都只能在同步或同步代码块中用,否则有异常

猜你喜欢

转载自blog.csdn.net/weixin_44905070/article/details/104799208
今日推荐