Java-多线程

Posted 起风了1412

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java-多线程相关的知识,希望对你有一定的参考价值。

多线程

  • 什么是线程和进程?

进程是系统运行程序的基本单位,在Java中启动一个main函数就是启动一个JVM进程,main函数所在的线程叫主线程.

线程是一个比进程还小的执行单位,一个进程可以产生多个线程.

总结 : 进程间是互相独立的,线程间是共享进程的空间,所以线程会有并发问题.

JVM

  • 运行时数据区域

线程私有 : 程序计数器,虚拟机栈,本地方法栈

线程共享 : 堆,方法区,直接内存

  • 程序计数器

主要有2个作用:
1. 字节码解释器通过改变程序计数器来决定下一条指令,从而控制代码流程.
2. 多线程情况下,程序计数器用来记录当前线程执行的位置,当线程切换回来的时候可以继续之前的流程,所以程序计数器是私有的.

  • Java 虚拟机栈

线程私有,Java内存大致可以分为堆区和栈区,栈区指的就是虚拟机栈,一般用来局部变量.

虚拟机栈可以出现的异常:
1. StackOverFlowError 当前线程请求栈的深度超过了虚拟机栈的最大深度.
2. OutOfMemoryError 当请求栈时,内存用完了且无法拓展时.

  • 本地方法栈

线程私有,和虚拟机栈类似,区别是主要为 Native 方法服务.

虚拟机管理的内存中最大的一块,线程共享.垃圾回收管理的主要区域,所以也成为GC堆.几乎所有的对象实例以及数组都在这分配内存.

  • 方法区

线程共享,主要存放被虚拟机加载的类的信息,常量,静态变量等.

多线程

  • 虚拟机栈和本地?法栈为什么是私有的?

这两个栈都是用来存放局部变量的,所以私有是为了防止别的线程访问到当前线程的局部变量.

  • 说说并发与并?的区别?
  1. 并发:一段时间内,多个任务都在执行.(单位时间内,只有一个任务在执行.)
  2. 并行:单位时间内,多个任务同时执行.
  • 什么是上下?切换?

当一个线程的时间片用完的时候就会变成就绪态,让其他线程使用,这个过程就是一次上下文切换.

  • 什么是线程死锁?如何避免死锁?

线程1拥有资源A,线程2拥有资源B,此时线程1去申请资源B,由于B已经被线程2持有,所以线程1进入阻塞等待状态,并且不会主动释放所持有的资源A,这就叫死锁.

  • 如何避免线程死锁?

产生死锁的条件:

  1. 互斥条件 : 该资源某一时刻只能被一个线程所持有.
  2. 请求与保持条件 : 进程因为请求资源而阻塞时,已持有的资源保持不放.
  3. 不剥夺条件 : 线程所持有的资源除非自己主动释放,否则一直持有,其他线程无法强行剥夺.
  4. 循环等待条件 : 多个线程形成一个资源循环等待环.

避免死锁,破坏条件:

  1. 破坏互斥条件 : 无法破坏,因为锁的本意就是让资源在一段时间内只能被一个线程所持有.
  2. 破坏请求与保持条件 : 一次性申请所有资源.
  3. 破坏不剥夺条件 : 当线程申请资源失败的时候,释放自己所持有的资源.
  4. 破坏循环等待条件 : 按顺序申请资源.
  • sleep() ?法和 wait() ?法区别?
  1. sleep不会释放锁,wait会释放锁.
  2. 都可以暂停线程.
  3. wait调用后不会自动苏醒,需要别的线程调用notify()唤醒,但是可以使用wait(long timeout)超时自动苏醒.
  • 为什么我们调? start() ?法时会执? run() ?法,为什么我们不能直接调? run() ?法?

调用start()时,会启动一个线程,当线程获得CPU时间时执行run()里面的内容;直接调用run(),会把run()当初main()下的一个普通方法去执行.

  • synchronized关键字最主要的三种使??式?
  1. 修饰实例(普通)方法 : 给当前实例对象加锁.
//假设 Demo 类的 demo() 被 synchronized 修饰
//例1 : 线程1,2抢占的是同一把锁,只能有一个线程持有.
public static void main(String[] args) {
       Demo demo = new Demo();
       Thread thread1 = new Thread(new MyThread(demo));
       Thread thread2 = new Thread(new MyThread(demo));
       thread1.start();
       thread2.start();
}

//例2 : 线程1,2抢占的是两把锁
public static void main(String[] args) {
       Demo demo1 = new Demo();
       Demo demo2 = new Demo();
       Thread thread1 = new Thread(new MyThread(demo1));
       Thread thread2 = new Thread(new MyThread(demo2));
       thread1.start();
       thread2.start();
}
  1. 修饰静态方法 : 给当前类加锁,作用于类的所有实例对象.

修饰静态方法后上面不论是例1还是例2都是抢占一个锁.

  1. 修饰代码块 : 给指定对象加锁.
  • synchronized 关键字的底层原理?

    synchronized 关键字属于JVM层面.
    
    通过查看字节码信息可以发现, synchronized 锁定代码的前后分别是 monitorenter 和  monitorexit ;当执行 monitorenter 时,线程去尝试获取锁(monitor,它存在于每个Java对象的头部,
    所以Java对象都可以作为锁.),当计数器为0时获取成功,然后将计数器加1;执行 monitorexit 时,计数器减一. 如果锁获取失败,那么当前线程就一直等待,直到锁被另一个线程释放.

以上是关于Java-多线程的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程与并发库高级应用-工具类介绍

多线程 Thread 线程同步 synchronized

Java多线程具体解释

自己开发的在线视频下载工具,基于Java多线程

什么是JAVA的多线程?

多个用户访问同一段代码