1如何创建线程

创建多线程实现类MyThread extends Thread,继承Thread后重载run()方法,在调用类中创建对象后调用start()方法执行该线程。

创建实现类MyThread implements Runnable,先new一个接口类,然后创建Thread类利用构造方法放入实现runnable接口的类 Thread thread = new Thread(myThread);然后调用thread.start()。

start() 方法会新建一个线程并让这个线程执行 run() 方法;而直接调用 run() 方法知识作为一个普通的方法调用而已,它只会在当前线程中,串行执行 run() 中的代码。

2.进程与线程的关系和区别

进程 :

进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。

线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。

线程 :

线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

程序是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。。

区别:地址空间、资源拥有

线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源

每个进程都有自己一套独立的资源(数据),供其内的所有线程共享

不论是大小,开销线程要更“轻量级”

一个进程内的线程通信比进程之间的通信更快速,有效。(因为共享变量)

线程调度 :

分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间

抢占式调度:优先级高的线程先使用CPU,如果优先级相同则随机选择一个

3.并发与并行

并发 :指两个或多个事件在同一时间段内发生。(交替执行)

并行 :指两个或多个事件在同一时刻发生(同时发生),cpu多个线程执行

4.实现同步的三种方法

同步代码块 :

格式:

synchronized(锁对象){

可能会出现线程安全的代码(访问了共享数据的代码)

}

通过代码块中的锁对象,可以使用任意的对象

但是必须保证多个线程使用的锁对象是同一个

把要同步访问的代码块锁住,只让一个线程在synchronized的代码块中执行,同步中的线程没有执行完毕不会释放锁,其他线程阻塞。

同步方法:

使用synchronized修饰的方法,保证线程执行该 方法的时候,其他线程只能在外面等待。run()中调用同步方法。

Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。锁的是this 即是这个对象

public synchronized void method(){

可能会产生线程安全的代码

}

静态同步方法

Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。

因为对静态对象加锁实际上对类(.class)加锁,类对象只有一个,可以理解为任何时候都只有一个空间,里面有N个房间,一把锁,因此房间(同步方法)之间一定是互斥的。

public synchronized static void staticMethod1(){

可能产生问题的代码块

}

5.Lock接口

lock实现比synchronized更广泛的锁操作

在成员位置创建一个ReentrantLock(实现类)对象

在可能会出现安全问题的代码前调用lock()方法获取锁

在可能会出现安全问题的代码后调用unlock()方法释放锁

6.wait()和sleep()方法区别

对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。

sleep()方法必须传入参数,参数就是休眠时间,睡眠后如果CPU空闲就会进入运行状态。

wait()方法可以传入参数也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不传入参数就是直接等待。需要调用notify()方法后本线程才进入对象锁定池准备(Runnable/Blocked)

两种状态合称冻结状态

7.多线程产生死锁的4个必要条件

互斥条件:一个资源每次只能被一个线程使用;

请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放;

不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺;

循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

如何避免死锁?

答:指定获取锁的顺序,举例如下:

比如某个线程只有获得 A 锁和 B 锁才能对某资源进行操作,在多线程条件下,如何避免死锁?

获得锁的顺序是一定的,比如规定,只有获得 A 锁的线程才有资格获取 B 锁,按顺序获取锁就可以避免死锁!!!

银行家算法:银行家算法是一种最有代表性的避免[死锁]的算法。在避免死锁方法中允许进程动态地申请资源,但系统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构

如何排查死锁

8.对synchronized关键字的理解

synchronized关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。

另外,在 Java 早期版本中,synchronized属于重量级锁,效率低下,因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock 来实现的,Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成,而操作系统实现线程之间的切换时需要从用户态转换到内核态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,这也是为什么早期的 synchronized 效率低的原因。庆幸的是在 Java 6 之后 Java 官方对从 JVM 层面对synchronized 较大优化,所以现在的 synchronized 锁效率也优化得很不错了。JDK1.6对锁的实现引入了大量的优化,如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销。

synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。

当执行 monitorenter 指令时,线程试图获取锁也就是获取 monitor(monitor对象存在于每个Java对象的对象头中,synchronized 锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因) 的持有权。当计数器为0则可以成功获取,获取后将锁计数器设为1也就是加1。相应的在执行 monitorexit 指令后,将锁计数器设为0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。

9.线程池

一个装满了Thread的集合(容器),其中的线程可以重复使用,省去了频繁创建线程对象的操作,无需因反复创建线程而消耗过多的资源。

java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类

三种最常见线程池

使用线程池工厂类Executors中的静态方法newFixedThreadPool(nThreads)来创建一个线程池

ExecutorService es = Executors.newFixedThreadPool(2); 定长nThreads 最大nThreads

无限线程池

ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 定长0 最大Integer.MAX_VALUE

单个线程线程池

Executors.newSingleThreadExecutor(); 定长1 最大1

如创建newCachedThreadPool,在实际上都是用ThreadPoolExecutor来返回的

public static ExecutorService newCachedThreadPool() {

return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

60L, TimeUnit.SECONDS,

new SynchronousQueue());

}

看看ThreadPoolExecutor的API

public ThreadPoolExecutor(int corePoolSize, 线程池的基本大小

int maximumPoolSize, 线程池的最大线程

long keepAliveTime, 线程空闲后的存活时间

TimeUnit unit, 线程空闲后的存活时间

defaultHandler, 队列和最大线程池满了后的饱和策略

BlockingQueue workQueue,

ThreadFactory threadFactory) {

this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

threadFactory, defaultHandler);

}

如果直接new ThreadPoolExecutor()需要自己装配这几个参数

ThreadPoolExecutor.execute(new Job()); 提交一个任务到线程池中

看看excute()的源代码

int c = ctl.get(); 获取当前线程状态

if (workerCountOf(c) < corePoolSize) { 当前线程数量

if (addWorker(command, true))

return;

c = ctl.get();

}

if (isRunning(c) && workQueue.offer(command)) { 当前线程处于运行状态,并且写入阻塞队列成功

int recheck = ctl.get();

if (! isRunning(recheck) && remove(command)) 双重检查,再次获取线程状态;如果线程状态变了(非运行状态)就需要从阻塞队列移除任务,并尝试判断线程是否全部执行完毕。同时执行拒绝策略。

reject(command);

else if (workerCountOf(recheck) == 0) 当前线程池为空创建一个新线程

addWorker(null, false);

}

else if (!addWorker(command, false)) 如果在第三步的判断为非运行状态,尝试新建线程,如果失败则执行拒绝策略。

reject(command);

这里借助《聊聊并发》的一张图来描述这个流程:

image.png

关闭线程池

shutdown() 执行后停止接受新任务,会把队列的任务执行完毕。

shutdownNow() 也是停止接受新任务,但会中断所有的任务,将线程池状态变为 stop。

10.synchronized与lock的区别

类锁: 一个LockServer.class ,此时输出不会重复

OrderService orderService = new OrderLockService();

for (int i = 0; i < 10; i++) {

executorService.submit(new OrderTask(latch,orderService));

}

对象锁: lockServer1、lockServer2、lockServer3,此时输出会重复

for (int i = 0; i < 10; i++) {

OrderService orderService = new OrderLockService();

executorService.submit(new OrderTask(latch,orderService));

}

原始构成

synchronized是底层关键字位于JVM层面,采用monitor对象来完成,其实wait/notify等方法也依赖于monitor对象只有在同步代码块或同步方法中才能调用wait/notify等方法(monitorenter/monitorexit)

lock是接口与具体的实现类,是api层面的锁

使用方法

synchronized不需要用户手动去释放锁,当synchronized代码执行王城后线程会自动释放对锁资源的占用。

Reentrantlock需要用户取手动释放锁如果没有主动释放锁就会出现思索地现象。

等待是否可中断

synchronized不可终端,需要抛出异常或者正常运行退出

Reentrantlock可中断,设置超时方法trylock(long timeout,TimeUnit unit)或者调用interrupt()方法中断

是否公平

synchronized是非公平锁

lock两者皆可,传入true为公平锁默认非公平

锁绑定多个条件Condition

lock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒。而不像notify()随即唤醒或者notifyAll()

java多线程面试_面试之JAVA多线程相关推荐

  1. java 字符串乱码_这份Java面试题含答案解析竟然真的让你不用在面试上“如履薄冰”...

    面试题集共分为以下十部分: 一.Core Java: 1 - 95 题1 - 24 页 基础及语法: 1 - 61 题1 - 13 页 异常: 62 - 69 题13 - 15 页 集合: 70 - ...

  2. java semaphore(0)_面试官:说说Java中的信号量?Semaphore

    Semaphore (信号量)是由计算机科学家Dijkstra在1965年提出的,广泛应用不同的操作系统,在管程提出之前信号量就是并发编程领域的霸主!几乎所有并发的语言都支持信号量机制. Semaph ...

  3. 顺丰java面试题_顺丰java开发面试分享,顺丰java面试经面试题

    今天要给大家分享的是一个小伙伴的顺丰java开发面试过程,其中包括了面试流程,面试题目,和回答,感兴趣的朋友可以来了解一下哈. 一.面试流程 是中午进行的面试,首先是做自我介绍,之后就是讲一下项目,然 ...

  4. java 线程 原子性_深入理解Java多线程与并发框架——Java内存模型与原子性、可见性、有序性...

    欢迎关注专栏<Java架构筑基>--专注于Java技术的研究与分享!Java架构筑基​zhuanlan.zhihu.comJava架构筑基--专注于Java技术的研究与分享! 后续文章将首 ...

  5. java多线程实例_要把Java吃透您得先吃透这些基本概念

    学习好比盖房子,打地基好很重要,房了能盖多高关键看地基:学习同样道理,基础知识是以后学习一切技术的必要条件,我们在准备学习一门开发语言时,首先要学习它的基础,不仅要会,更要融会贯通:万变不离其宗,无论 ...

  6. 南方航空java面试_面试经验 南航面试经历分享

    南方航空面试经历分享 前言 每个人的成功经验都是来之不易的,今天小V的面经写得有点长,为了给大家写的详细一些,参考多一些,也是拼了! 小V的基本情况:小V是一名大三的在校学生,学的还是搬砖的理工科专业 ...

  7. java在线编译器_什么是Java内存模型

    在知识星球中,有个小伙伴提了一个问题:有一个关于JVM名词定义的问题,说"JVM内存模型",有人会说是关于JVM内存分布(堆栈,方法区等)这些介绍,也有地方说(深入理解JVM虚拟机 ...

  8. java编程学习方法_在线学习Java编程的最佳方法

    java编程学习方法 1.简介 Java是使用最广泛的编程语言之一. 根据Github的最新报告 ,Java被列为仅次于JavaScript的第二大最常用的编程语言. 掌握Java的人有很多话题. 好 ...

  9. java设计模式并发_[高并发Java 七] 并发设计模式

    [高并发Java 七] 并发设计模式 [高并发Java 七] 并发设计模式 为什么80%的码农都做不了架构师?>>> 在软件工程中,设计模式(design pattern)是对软件设 ...

  10. 用友java面试题_用友网络科技Java高级开发面试题(2019)

    面试岗位:Java高级开发 面试形式:电话面试 这些天在boss上逛了下,看见北京Java开发工资比较诱人,便萌生了去北京的想法,做一名北漂的程序猿.约了几家面试,由于是异地,当然优先电话面了.本篇记 ...

最新文章

  1. 一行代码简化Python异常信息:错误清晰指出,排版简洁美观 | 开源分享
  2. combobox数据获取及使用总结
  3. 数据库工作笔记009---Centos中导出mysql数据库
  4. 速升级 Microsoft Word……且慢!
  5. Atitit hi dev eff topic by use dsl sql coll op 提升开发效率sql dsl查询内存集合列表 目录 1.1. Dsl api lib 1 1.2. R
  6. AutoJs学习-实现极乐净土
  7. zookeeper学习一-ZK简介
  8. 【BZOJ5285】【HNOI2018】寻宝游戏
  9. siri 语义识别_如何查看使用Siri识别的歌曲列表
  10. csharp 在万年历中计算显示农历日子出错
  11. Visual Leak Detector使用方法
  12. TypeError: only integer tensors of a single element can be converted to an index
  13. HACKTHEBOX——Help
  14. MySQL大厂优化方案轻松应对高并发!真牛!
  15. 第四章 证券投资基金的监管
  16. 高可用性HA(High Availability)双机热备
  17. java实现九宫格解锁_Java计算手机九宫格锁屏图案连接9个点的方案总数
  18. 聊聊身边的嵌入式,自拍神器自拍杆
  19. 算法训练 Cowboys(DP)
  20. 【补充】Linux-2.6.22.6 makefiles.txt翻译

热门文章

  1. libtorch Compiler Error C2951
  2. python 二维 排序
  3. 复数的物理意义是什么
  4. 锐捷路由器--多线路应用路由
  5. android listview分页显示,Android应用中使用ListView来分页显示刷新的内容
  6. 服务器支持curl,互联网要点:服务器不支持curl_exec的解决办法
  7. (一)TestNG测试框架之HelloWorld入门
  8. CentOS6.3环境下openresty安装drizzle模块
  9. linux中时间戳与date的互转
  10. php解析QQmv直链,网易云音乐直链解析API源代码^-^