zoukankan      html  css  js  c++  java
  • 多线程与并发(一)——概述、线程状态

    iwehdio的博客园:https://www.cnblogs.com/iwehdio/

    1、多线程概述

    • 多线程:多条执行路径,主线程和子线程并行交替执行。

    • 进程:是执行程序的一次执行过程,是系统资源分配的单位。在操作系统中运行的程序就是进程。

    • 线程:是独立的执行路径,是CPU调度和执行的单位。一个进程可以有多个线程。

    • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度。

    • 对于同一份资源操作,会存在资源抢夺的问题,需要加入并发控制。

    • 线程创建:

      • 三种方法:继承Thread类、实现Runnable接口或实现Callable接口。

      • 继承Thread类:

        • Thread类实现了Runnable接口。

        • 自定义线程类继承Thread类,重写run()方法,编写线程 执行体。创建线程对象,调用start()方法启动线程。

          public class TestThread01 extends Thread {
          
              @Override
              public void run() {
                  //线程体
                  for (int i = 0; i < 200; i++) {
                      System.out.println("子线程--" + i);
                  }
              }
          
              public static void main(String[] args) {
                  TestThread01 thread01 = new TestThread01();
                  thread01.start();
                  for (int i = 0; i < 1000; i++) {
                      System.out.println("主线程--" + i);
                  }
              }
          }
          
        • 线程开启不一定立即执行,由CPU调度执行。主线程和子线程是交替执行的。

      • 实现Runnable接口:

        • 实现run()方法,编写线程执行体。创建线程对象(传入实现类),调用start()方法启动线程。

          public class TestThread02 implements Runnable {
          
              @Override
              public void run() {
                  for (int i = 0; i < 200; i++) {
                      System.out.println("子线程--" + i);
                  }
              }
          
              public static void main(String[] args) {
                  TestThread02 thread02 = new TestThread02();
                  //传入实现类
                  new Thread(thread02).start();
                  for (int i = 0; i < 1000; i++) {
                      System.out.println("主线程--" + i);
                  }
              }
          }
          
        • Java是单继承多实现,推荐使用实现Runnable接口的方法,方便一个对象被多个线程调用。

      • 实现Callable接口:

    • 初识并发问题:

      • 多个线程操作同一个资源的情况下,线程不安全,数据紊乱。

        public class TestThread03 implements Runnable {
        
            private int ticketNum = 10;
            @Override
            public void run() {
                while (true) {
                    if(ticketNum<=0) {
                        break;
                    }
                    //延时
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
         			//获取当前运行的线程名称          
                    System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNum--+"张票");
                }
            }
        
            public static void main(String[] args) {
                TestThread03 testThread03 = new TestThread03();
        		//同一个对象传入多个线程,设置线程名字
                new Thread(testThread03,"线程A").start();
                new Thread(testThread03,"线程B").start();
                new Thread(testThread03,"线程C").start();
            }
        }
        

    2、先备知识

    • 静态代理:

      • 代理对象和真实对象都要实现同一个接口。代理对象要代理真实对象。

      • 代理对象做真实对象做不了的事情,真实对象专注做自己的事情。

      • Thread对象和传入的线程对象都实现了Runnable接口,Thread对象时传入的线程对象的静态代理。

        public class TestThread04 {
            public static void main(String[] args) {
                //类比 new Thread(testThread).start();
                new WeddingCompany(new You()).HappyMarry();
            }
        }
        
        
        interface Marry {
            public void HappyMarry();
        }
        
        class You implements Marry{
        
            @Override
            public void HappyMarry() {
                System.out.println("Marry");
            }
        }
        
        class WeddingCompany implements Marry{
            private Marry target;
        
            public WeddingCompany(Marry target) {
                this.target=target;
            }
        
            @Override
            public void HappyMarry() {
                before();
                this.target.HappyMarry();
                after();
            }
        
            private void after() {
                System.out.println("after");
            }
        
            private void before() {
                System.out.println("before");
            }
        }
        
    • Lamda表达式:

      • 避免匿名内部类定义过多,属于函数式编程的概念。

      • 函数式接口:只包含一个抽象方法的接口。

      • Lamda表达式的简化过程:

        • 外部实现类 -> 静态内部类 -> 局部内部类 -> 匿名内部类 -> Lamda表达式。
        public class LamdaFunction {
            //3、静态内部类
            static class ILike2 implements Like {
                @Override
                public void lamda(int p) {
                    System.out.println("静态内部类"+ p);
                }
            }
            public static void main(String[] args) {
                Like like1 = new ILike1();
                like1.lamda(1);
                Like like2 = new ILike2();
                like2.lamda(2);
                //4、局部内部类
                class ILike3 implements Like {
                    @Override
                    public void lamda(int p) {
                        System.out.println("局部内部类"+ p);
                    }
                }
                Like like3 = new ILike3();
                like2.lamda(3);
                //5、匿名内部类
                Like like4 = new Like() {
                    @Override
                    public void lamda(int p) {
                        System.out.println("匿名内部类"+ p);
                    }
                };
                like4.lamda(4);
                //6、Lamda表达式
                Like like5 = (int p) -> {
                    System.out.println("Lamda表达式"+ p);
                };
                like5.lamda(5);
                //7、简化的Lamda表达式
                Like like6 = p -> System.out.println("简化的Lamda表达式"+ p);
                like6.lamda(6);
            }
        }
        //1、函数式接口
        interface Like {
            public void lamda(int p);
        }
        //2、外部实现类
        class ILike1 implements Like {
            @Override
            public void lamda(int p) {
                System.out.println("外部实现类"+ p);
            }
        }
        

    3、线程状态

    • 线程状态:

    • 线程停止:

      • 不推荐使用JDK提供的已经过时的线程停止方法。
      • 建议线程正常停止。可以使用标志位,对外提供方法改变表示,使线程停止下来。
      public class TestStop implements Runnable {
          private boolean flag = true;
          @Override
          public void run() {
              int i = 0;
              while (flag){
                  System.out.println("thread run..." + i++);
              }
          }
      
          public void stop(){
              this.flag=false;
          }
      
          public static void main(String[] args) {
              TestStop testStop = new TestStop();
              new Thread(testStop).start();
              for (int i = 0; i < 100; i++) {
                  System.out.println("main线程" + i);
                  if(i==90){
                      testStop.stop();
                      System.out.println("线程停止");
                  }
              }
          }
      }
      
    • 线程休眠:

      • Thread.sleep()指定当前线程阻塞的毫秒数。存在异常InterruptedException。
      • 时间达到后线程进入就绪状态。
      • 每一个对象都有一个锁,sleep不会释放锁。
    • 线程礼让:

      • Thread.yield()礼让线程,让正在执行的线程暂停,但不阻塞。
      • 将线程从运行状态转为就绪状态。
      • CPU重新调度,礼让不一定成功。
    • 线程强制执行:

      • thread.join()合并线程,待此线程执行完成之后,再执行其他线程,其他线程阻塞。可以理解为插队。

        public class TestJoin implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("子线程join" + i);
                }
            }
        
            public static void main(String[] args) throws InterruptedException {
                TestJoin testJoin = new TestJoin();
                Thread thread = new Thread(testJoin);
                thread.start();
                for (int i = 0; i < 200; i++) {
                    if(i==100) {
                        thread.join();
                    }
                    System.out.println("main线程" + i);
                }
            }
        }
        
      • 线程在main线程执行到100之前都是CPU调度的,执行到100之后先执行子线程,main线程阻塞。

    • 观测线程状态:

      • Thread.State常量定义线程状态:

        • NEW:新生,尚未启动的线程。
        • RUNNABLE:Java虚拟机中执行的线程。
        • BLOCKED:被阻塞等待监视器锁定的线程。
        • WAITING:正在等待另一个线程执行特定动作的线程。
        • TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程。
        • TERMINATED:已经退出的线程。
        public class TestState implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
        
                }
            }
        
            public static void main(String[] args) throws InterruptedException {
                TestState testState = new TestState();
                Thread thread = new Thread(testState);
        
                Thread.State state = thread.getState();
                System.out.println(state);
        
                thread.start();
                state = thread.getState();
                System.out.println(state);
        
                while (thread.getState()!=Thread.State.TERMINATED) {
                    Thread.sleep(100);
                    state = thread.getState();
                    System.out.println(state);
                }
                state = thread.getState();
                System.out.println(state);
            }
        }
        
    • 线程优先级:

      • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器安装优先级判断应该调度那个线程来执行。
      • 线程优先级高只是意味着获得调度的概率低,更可能优先执行,不是一定优先执行。
      • 线程的优先级用数字表示,范围从1到10。常量包括:
        • Thread.MIN_PRIORITY=1
        • Thread.MAX_PRIORITY=10
        • Thread.NORM_PRIORITY=5.
      • 使用方法getPriority()来获取优先级。
      • 使用方法setPriority(int xxx)来设置优先级。
    • 守护线程:

      • 线程分为用户线程和守护(daemon)线程。
      • 虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕。
      • 设置线程为守护线程thread.setDaemon(true)

    iwehdio的博客园:https://www.cnblogs.com/iwehdio/
    来源与结束于否定之否定。
  • 相关阅读:
    使用基于关系的选择器和伪类选择器创建纯CSS无JavaScript的鼠标移动到上面即可显示的下拉菜单
    git学习教程
    笔记
    luogu P1429 平面最近点对(加强版)
    可持久化数据结构
    luogu P4137 Rmq Problem / mex
    置换群(Burnside引理+Polya定理)
    luogu P1053 篝火晚会
    luogu P3238 [HNOI2014]道路堵塞
    luogu P3812 【模板】线性基
  • 原文地址:https://www.cnblogs.com/iwehdio/p/13561593.html
Copyright © 2011-2022 走看看