欢迎来到知了汇智!
联系电话:知了汇智-电话号码 028-62016472 / 13228113191

深度解析线程是什么?为什么使用多线程?-知了汇智

深度解析线程是什么?为什么使用多线程?

  线程在面试中已经是常客了,也是我们必备的知识点,关于线程,问的最多的便是线程是什么?为什么使用多线程?多线程的示例以及解决方案?线程池是什么?

  一.线程是什么?

  Thread类中有这样的明确定义:线程是程序中执行的线程,Java虚拟机允许程序同时运行多个执行线程。

  具有较高优先级的线程优先于优先级较低的线程执行,每个线程可能也可能不会被标记为守护进程。当在某个线程中运行创建一个新的 Thread对象时,新的线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时才是守护进程线程。

  (线程的优先级用数字来表示,范围从1~10,主线程的默认优先级为5 :

  Thread.MIN_PRIORITY=1;Thread.MAX_PRIORITY=10;Thread.NORM_PRIORITY=5

  当Java虚拟机启动时,通常会有一个非守护程序线程(通常调用某个指定类的名为 main的方法)

  Java虚拟机继续执行线程直到发生以下任一情况:

  已调用类 Runtime的exit方法,并且安全管理器已允许执行退出操作。

  所有非守护程序线程的线程都已经死亡,要么通过调用返回run方法,要么抛出一个超出run 方法传播的异常。

  问:线程与进程?:进程是CPU,内存等资源占用的基本单位,线程是不能独立占有这些资源的;进程之间相互独立,通信比较困难,线程之间共享一块内存区域,通信方便

  二.怎么创建一个线程呢?

  Thread中规定:有两种方法可以创建新的执行线程。

  声明一个类是Thread类,该子类还应该覆盖Thread类中的run方法,然后可以分配并启动子类的示例。

  class MyThread extends Thread {
  @Override
  public void run() {
  //具体的方法
  System.out.println(Calendar.getInstance().getTime());//系统时间
  }
  }

  然后创建一个线程并开始运行:

  MyThread myThread=new MyThread();
  myThread.start();

  声明一个实现 Runnable接口的类, 该类然后实现 run 方法, 然后可以分配类的实例,在创建 Thread时作为参数传递,然后启动。

  class MyThreard implements Runnable {
  public void run() {
  System.out.println(Calendar.getInstance().getTime());
  }
  }

  然后创建一个线程并开始运行:

  MyThreard p = new MyThreard();
  new Thread(p).start();

  三.为什么使用多线程?

  多线程指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务

  更高的运行效率,——并行;

  多线程是模块化的编程模型;

  与进程相比,线程的创建和切换开销更小;

  通信方便;

  能简化程序的结构,便于理解和维护;更高的资源利用率。

  注:多线程上下文切换的性能损耗:上下文切换(线程切换,进程切换,模式切换,地址空间切换)——中断处理(硬件中断,软件中断—线程被挂起);多任务处理(每个程序都有相应的处理时间片);用户态切换。

  四.多线程的安全问题

  简单测试你的线程是否安全:如果你的代码在多线程下执行和在单线程下执行永远都能获得一样的结果,那么你的代码就是线程安全的。

  如果不一致,那就可能是多线程的资源安全有问题,常见的情况如下:

  1.临界资源问题:多个线程同时访问相同的资源并进行读写操作

  解决思路:避免竞态条件;多线程同步,必须获得每一个线程对象的锁(lock)

  示例代码(一个线程进行加操作,一个线程进行减操作):

  public class Stack {
  int idx=0;
  char[] data=new char[10];
  public void push(char c) {
  synchronized (this) {//在执行该代码段时必须取得对象锁
  data[idx]=c;
  idx++;     }
  }
  public synchronized char pop() {//在执行该方法时必须取得对象锁
  idx--;
  return data[idx];
  }
  }

  同步实现的方法:

深度解析线程是什么?为什么使用多线程?


  生产消费者模式:一个线程负责生产数据,放到共享区域,然后通知另一个线程去消耗数据。

  (1)用wait()和notify():这样消费者线程就不用不停去检查是否有数据被产生。

深度解析线程是什么?为什么使用多线程?

 

  (2)用阻塞队列实现:BlockingQueue中提供了put()和take()方法,可以极大简化生产者消费者模式的实现过程。这一过程的基本原理是,如果队列满了,put()方法就会被阻塞;如果队列是空的,take()方法会阻塞。与传统的wait()和notify()方法相比,使用阻塞队列更简单,更便于理解。

  2.死锁:死锁也是一种因为对资源争夺而出现的状态,是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们将一直互相等待而无法推进下去。不断地加锁,锁中锁,锁套锁,最后造成循环,就可能会成为死锁;因此要解决死锁,尽量避免对同一资源的剥夺,请求和保持,避免循环等待。

  五.线程池

  目的是减小对象的创建和注销的开支,减轻JVM的压力。

  1)避免线程的创建和销毁带来的性能开销。

  2)避免大量的线程间因互相抢占系统资源导致的阻塞现象。

  3}能够对线程进行简单的管理并提供定时执行、间隔执行等功能。

  主要有四个:

  ThreadPool–>线程池管理器:用于创建并管理线程池(创建线程池,销毁线程池,添加新任务);

  PoolWorker–>工作线程

  Task–>任务接口,每个接口必须实现的接口

  TaskQue–>任务队列,用于存放没有处理的任务;提供一种缓冲机制
 

  版权声明:本文来源于网络,由知了堂搜集整理,仅供大家学习Java时使用

132 2811 3191
预约免费试学
点击咨询
预约试学