多线程和并发

85 阅读5分钟
Java怎么保证多线程运行安全?
Java中线程安全体现在以下三个方面
原子性
可见性
有序性
因此, 只要满足这三个条件, 我们就可以说代码是线程安全的。
在Java中, 解决方案有
使用sychronized关键字
使用线程安全类, 如java.util.concurrent包下的类
使用并发包下的Lock相关锁。
线程和进程的区别?Java实现的多线程的方式有哪几种?

进程指的就是一个内存中运行的应用程序(程序的一次运行就会产生一个进程)。 线程指的就是进程中运行的一个任务。 进程与线程间存在包含关系,一个进程至少有一个线程,一个进程可运行多个线程,多个线程可共享进程的数据。

创建线程的方式:

  1. 继承Thread类,重写run方法
  2. 实现Runnable接口, 重写run方法
  3. 通过Callable和FutrueTask创建
  4. 通过线程池创建
线程有哪些基本状态(生命周期),并描述一下。
状态描述
初始状态线程被创建,此时还没有调用start()方法。
就绪状态线程处于就绪队列,等待系统为其分配cpu。
运行状态在运行状态的线程执行自己的run方法中代码,直到等待某资源而阻塞或完成任务而死亡。
终止状态表示当前线程已经执行完毕
同步和异步的区别

同步:单线程执行,多线程异步执行 异步:在多线程场景下,主线程继续处理任务,额外的任务交由其他线程处理,实现任务并行处理。

并发与并行的区别

并发: 在同一时间段内执行多个任务 并行: 在同一时间点执行多个任务

线程的run()和start()的区别?

start(): 它的作用是启动一个新线程。 通过start()方法来启动的线程,处于就绪状态,并没有并没有运行,一旦得到cpu时间片,就开始执行相应线程的run()方法,这里方法run()称为线程体,它包含了要执行的这个线程的内容,run方法运行结束,此线程随即终止。 start()不能被重复调用。用start方法来启动线程,真正实现了多线程运行,即无需等待某个线程run方法体代码执行完毕就直接继续执行下面的代码。这里无需等待run方法执行完毕,即可继续执行下面的代码,即进行了线程切换。

run(): run()就和普通的成员方法一样,可以被重复调用。 如果直接调用run()方法,并不会启动新线程!程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到多线程的目的。 总结:调用start方法可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。

说一下runnable和callable有什么区别?
  1. 最大的区别,runable没有返回值,而实现callable的任务线程能返回执行结果。
  2. callable的实现类中的run方法允许异常向上抛出,也可以在内部通过try catch捕获异常,而runnable的实现类中的run方法只能在内部通过try catch捕获异常,不能抛出。
什么线程死锁,产生死锁的原因是什么?

所谓死锁就是一组相互竞争、争夺资源的线程因相互等待导致" 永久 "阻塞的现象。 产生死锁的原因有四个: 第一是互斥条件:共享资源在任意时刻只能被一个线程占有 第二是占有且等待:线程T1占有共享资源X,在等待共享资源Y的时候,不释放共享资源X 第三是不可抢占:其他线程不能强行抢占线程T1占有的资源 第四是循环等待:线程T1等待线程T2占有的资源 线程T2等待线程T1占有的资源

如何避免线程死锁?

既然发生死锁的原因是需要同时满足这四个条件,我们只需要打破其中任意一个条件即可避免线程死锁问题。 而在这四个条件中,第一个互斥条件是无法破坏的,因为锁本身就是通过互斥来解决线程安全问题的,所以对于剩下三个,我们可以逐一进行分析。 第一个是对于“占用且等待”这个条件,我们可以一次性申请所有的资源,这样就不存在等待了。 第二个是对于“不可抢占”这个条件,占用部分资源的线程,进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就破坏掉了。 第三个对于“循环等待”这个条件,可以靠按序申请资源来进行预防,所谓按序申请是指资源是有线性顺序的,申请的时候可以先申请资源序号小的,再申请资源序号大的,这样线性化后自然就不存在循环等待了。

说说sleep()方法和wait()方法的区别和共同点?

两者最主要的区别在于,sleep没有释放锁,wait释放了锁。 两者都可以暂停线程的执行。 wait通常被用于线程的交互/通信;sleep通常被用于暂停线程执行。 wait()在被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或notifyAll()方法。 sleep()在执行完成后,线程会自动苏醒。或者可以使用wait(long timeout)超时后线程会自动苏醒。

volatile关键字
  • 保持内存可见性: 所有线程都能看到共享内存的最新状态
  • 防止指令重排