俗话讲,3月不跳槽,5月徒伤悲,到了八九月,就只能惦记着年终奖,又害怕新机会鸡飞蛋打 :)
今天主要内容是java的线程部分和java的锁。
1.什么是线程?进程和线程的关系是什么?
线程可定义为进程内的一个执行单位,或者定义为进程内的一个可调度实体。 在具有多线程机制的操作系统中,处理机调度的基本单位不是进程而是线程。
一个进程可以有多个线程,而且至少有一个可执行线程。
简单的说,进程是执行着的应用程序,而线程是进程内部的一个执行序列。一个进程可以有多个线程。线程又叫做轻量级进程。
线程和进程的关系:
线程是进程的一个组成部分.
进程的多个线程都在进程地址空间活动.
系统资源是分配给进程的,线程需要资源时,系统从进程的资源里分配给线程.
计算机调度的基本单位是线程.
线程上下文的切换比进程上下文切换要快很多
进程切换时,涉及到当前进程的CPU环境的保存和新被调度运行进程的CPU环境的设置。
线程切换仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作。
2.什么是线程安全和线程不安全?
简单的说,加锁的就是线程安全的,不加锁的是线程不安全的
线程安全:当多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问,直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
3.什么是多线程?
多线程就是多个线程同时运行或交替运行。
如果是单核CPU则是顺序执行,也就是交替运行。
如果是多核CPU,因为每个CPU有自己的运算器,所以在多个CPU中可以同时运行。
4.为什么要有多线程?
使用线程可以把占据长时间的程序中的任务放到后台去处理。
用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
程序的运行速度可能加快。
5.Java多线程有哪几类
用户线程:运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用户线程守护线程:运行在后台,为其他前台线程服务.一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作6、什么是多线程上下文切换
多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。
7.创建线程有几种不同的方式?
有三种方式可以用来创建线程:
继承Thread类实现Runnable接口应用程序可以使用Executor框架来创建线程池通常用实现Runnable接口这种方式创建线程,因为这不需要继承Thread类。
8.Thread 类中的start() 和 run() 方法有什么区别?
start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。
当调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。
9.直接调用start()方法时和直接调用run()方法有什么区别?
当我们new一个Thread,线程进入了新建状态;调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。
start()会执行线程的相应准备工作,然后自动执行run()方法的内容,这是真正的多线程工作。
而直接执行run()方法,会把run方法当成一个main线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
因此,调用start方法方可启动线程并使线程进入就绪状态,而run方法只是thread的一个普通方法调用,还是在主线程里执行。
10.对ThreadLocal的理解
ThreadLocal是一个创建线程局部变量的类。通常情况下我们创建的变量,可以被多个线程访问并修改,通过ThreadLocal创建的变量只能被当前线程访问。因为ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。
简单说,ThreadLocal就是一种以空间换时间的做法。在每个Thread里面维护了一个ThreadLocal.ThreadLocalMap把数据进行隔离,数据不共享,自然就没有线程安全方面的问题了.
11.ThreadLocal内部实现
ThreadLocal提供了set和get方法.
set方法会先获取当前线程,然后用当前线程作为句柄,获取ThreadLocaMap对象,并判断该对象是否为空,如果为空则创建一个,并设置值,不为空则直接设置值。
ThreadLocal并不会导致内存泄露,因为ThreadLocalMap中的key存储的是ThreadLocal实例的弱引用,因此如果应用使用了线程池,即便之前的线程实例处理完之后出于复用的目的依然存活,也不会产生内存泄露。
12.什么是线程安全?
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为。
线程安全的核心是“正确性”,也就是说当多个线程访问某个类时,能够得到预期的结果,那么就是线程安全的。
13、如何在两个线程间共享数据
通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAll、await/signal/signalAll进行唤起和等待。
比如说:阻塞队列BlockingQueue就是为线程之间共享数据而设计的
14、生产者消费者模型的作用是什么?
提高效率:通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率,这是生产者消费者模型最重要的作用
解耦:这是生产者消费者模型附带的作用,解耦意味着生产者和消费者之间的关联少,耦合越少就越可以独自发展而不需要收到相互的制约
15、java中的++操作符是线程安全的么?
不是线程安全的操作。
它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差