java多线程

JAVA多线程

进程和线程的区别

  1. 进程是执行程序的一次执行过程,是一个动态概念(例如QQ/微信进程)。是系统分配的单位

  2. 线程是CPU调度和执行的单位,线程之间互不影响;线程运行由cpu调度器安排,先后顺序不能人为干预;对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制;线程会带来额外的开销,如cpu调度时间;每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

  3. 一个进程可以有多个线程(最少有一个)

注意:很多多线程是模拟出来的,真正的多线程是指多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能做一件事,因为运行速度很快,所以就有了同时执行的错觉。

线程是程序中执行的线程,程序运行起来就变成了进程,进程中就有了线程!

线程三种创建方式

  1. 继承Thread类

    public class ThreadDemo extends Thread{ // 继承Thread类
       @Override
       public void run() { // 1.第一步 重写run方法
           for (int i = 0; i < 200; i++) {
               System.out.println("线程方法 --- " + i);
          }
      }
       public static void main(String[] args) {
           ThreadDemo threadDemo = new ThreadDemo(); // 2.第二步 创建线程对象
           threadDemo.start(); // 3.第三步 调用start方法启动线程
           //线程不一定立即执行,由cpu安排调度
           // 运行程序后会发现,线程方法 和 下面的for循环 是交叉输出,并行运行
           for (int i = 0; i < 300; i++) {
               System.out.println("Main方法 +++ " + i);
          }
      }
    }

    // 注意,这里不能使用 threadDemo.run()来启动线程,这样的会先执行线程方法,执行完成后才执行下面的for循环(从上到下一次执行)

    练习:通过继承Thread类实现多线程下载图片的功能

    https://www.cnblogs.com/auuv/articles/15734921.html

  2. *实现Runnable接口(推荐使用,原因:避免单继承的局限性,方便同一对象被多线程使用)

    public class TestRunnable implements Runnable { // 实现Runnable接口
       @Override
       public void run() { // 1.第一步 重写run方法
           for (int i = 0; i < 200; i++) {
               System.out.println("线程方法 --- " + i);
          }
      }
       public static void main(String[] args) {
           TestRunnable testRunnable = new TestRunnable();// 2.第二步 创建线程对象
           new Thread(testRunnable).start();// *3.第三步 调用start方法启动线程(只有第三步和继承Thread类方法不同)
           for (int i = 0; i < 300; i++) {
               System.out.println("Main方法 +++ " + i);
          }
      }
    }

    练习:通过实现Runnable接口实现多线程下载图片的功能

  3. 实现Callable接口(了解即可)

    public class TestCallable implements Callable<Boolean> { // 实现Callable接口
       @Override
       public Boolean call() { // 重写call方法 *需定义返回值Object
           return null;
      }
       public static void main(String[] args) throws ExecutionException, InterruptedException {
           TestCallable testCallable = new TestCallable(); // 1.实例化对象
           ExecutorService executorService = Executors.newFixedThreadPool(3);// 2.创建执行服务
           Future<Boolean> submit = executorService.submit(testCallable);// 3.提交执行
           Boolean aBoolean = submit.get();// 4.获取结果
           executorService.shutdown();// 5.关闭服务
      }
    }

线程运行状态

线程常用方法

  1. setPriority(int new Priority) 更改线程的优先级

  2. static void sleep(long millis) 线程休眠(每个对象都有一个锁,sleep不会释放锁)

  3. void join() 强制执行指定线程(插队,建议少用,容易造成线程阻塞)

  4. satic void yield() 暂停当前正在执行的线程(礼让不一定会成功,看cpu调度结果)

  5. void interrupt() 中断线程(不推荐使用)

  6. boolean isAlive() 判断线程是否处于活动状态

  7. *stop() / destroy() 让线程停止(不推荐使用)推荐使用一个标志位让线程自己终止

  8. getState() 获取线程状态 (Thread.State.常量值)


线程优先级

  1. Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度那个线程来执行。

  2. 线程的优先级用数字表示,范围从 1 - 10(不在该范围内会抛出异常)

  3. 优先级低只是意味着获得调度的概率低,并不是优先级低就不会被提前调用,主要看CPU的调度

  4. setPriority(int x) , getPriority() (设置优先级需在start()之前设置,优先级越高,权重机会越大。例如:分别在100张彩票和10张彩票中抽奖,100张彩票肯定比10张彩票的中奖率要大)

  5. 优先级默认值是5;Thread.MIN_PRIORITY=1,Thread.MAX_PRIORITY=10,Thread.NORM_PRIORITY = 5;


守护(daemon)线程

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

  2. 虚拟机必须确保用户线程执行完毕(平时创建的线程都是用户线程,例如main()主线程)

  3. 虚拟机不会关心守护线程是否执行完毕(例如gc,只要用户线程执行完毕,jvm就会关闭)

  4. setDaemon(boolean) 默认false为用户线程,true为守护线程

posted @ 2021-12-30 18:21  迷路小孩  阅读(34)  评论(0)    收藏  举报