线程与进程
线程与进程的关系
- 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位;
- 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
- 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信
号等),某进程内的线程在其他进程不可见; - 调度和切换:线程上下文切换比进程上下文切换要快得多
- 线程廉价,线程启动比较快,退出比较快,对系统资源的冲击也比较小。而且线程彼此分享了大部分核心对象(File Handle)的拥有权
简单说 就是说线程是进程的一部分一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
线程的5种状态
-
新建:新创建了一个线程对象。
-
可运行
-
运行
-
阻塞
4.1等待阻塞:运行(的线程执行**wait()**方法,JVM会把该线程放入等待队列中。
4.2. 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
4.3. 其他阻塞:运行的线程执行
Thread.sleep(long ms)或t.join() 方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。 -
死亡
创建一个线程的方法
1、继承Thread类
1 建一个类继承Thread类,重写run()方法;
2 创建Thread类的子类的对象;
3 调用该对象的start()方法,该start()方法表示先开启线程,然后调用run()方法
创建一个新线程
ThreadDemo1 thread1 = new ThreadDemo1();
2、实现Runnable接口
1 创建一个类并实现Runnable接口
2 重写run()方法,将所要完成的任务代码写进run()方法中
3、实现Callable接口
1 创建一个类并实现Callable接口
2 重写call()方法,将所要完成的任务的代码写进call()方法中
4、使用线程池创建
1 用Executors类中的newFixedThreadPool(int num)方法创建一个线程数量为num的线程池
线程安全
多线程编程中的三个核心概念
原子性:要么全部执行,要么全部都不执行(
可见性: 当多个线程并发访问共享变量时,一个线程对共享变量的修改,其它线程能够立即看到
顺序性 :程序执行的顺序按照代码的先后顺序执行
什么时候会出现线程安全
在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量、一个对象、一个文件、一个数据库表等,而当多个线程同时访问同一个资源的时候,就会存在一个问题:
1 .互斥锁:
当线程进入方法时,会自动获得一个锁,一旦锁被获得,其他线程必须等待获得锁的线程执行完代码释放锁,但是会降低程序的执行效率
怎么提示
2. ThreadLocal :为每个线程提供局部变量,解决线程安全问题
ThreadLocal 底层采用 Map 来实现,将当前线程作为key,将值存储到这个 map 中
======================================================
多线程中的安全问题
java语言中各种操作共享的数据分为以下5类
不可变
final关键字修饰的数据不可修改,可靠性最高
绝对线程安全
绝对的线程安全完全满足Brian GoetZ给出的线程安全的定义,这个定义其实是很严格的,一个类要达到不管运行时环境如何,调用者都不需要任何额外的同步措施”通常需要付出很大的代价
相对线程安全
字面意思 它需要保证对这个对象单独的操作是线程安全的,我们在调用的时候不需要做额外的保障措施,但是对于一些特定顺序的连续调用,就可能需要在调用端使用额外的同步手段来保证调用的正确性。
在java语言中,大部分的线程安全类都属于相对线程安全的,例如Vector、HashTable、Collections的synchronizedCollection()方法保证的集合
线程兼容和线程对立。
线程兼容就是我们通常意义上所讲的一个类不是线程安全的
====================================================
1 同步方法
synchronized
互斥同步最主要的问题就是进行线程阻塞和唤醒所带来的性能问题,因此这种同步也成为阻塞同步。从处理问题的方式上说,互斥同步属于一种悲观的并发策略,总是认为只要不去做正确地同步措施(例如加锁),那就肯定会出现问题,无论共享数据是否真的会出现竞争,它都要进行加锁
无需同步
要保证线程安全,并不是一定就要进行同步,两者没有因果关系。同步只是保证共享数据争用时的正确性的手段,如果一个方法本来就不涉及共享数据,那它自然就无需任何同步操作去保证正确性,因此会有一些代码天生就是线程安全的
重点 随机发挥
使用消费队列的架构模式(如“生产者-消费者”模式)都会将产品的消费过程尽量在一个线程中消费完。其中最重要的一个应用实例就是经典的Web交互模型中的“一个请求对应一个服务器线程(Thread-per-Request)”的处理方式,这种处理方式的广泛应用使得很多Web服务器应用都可以使用线程本地存储来解决线程安全问题
======================================================
线程池
1.为什么使用线程池 你在那些场景使用了它
Web 服务器、数据库服务器、文件服务器或邮件服务器 这些单个任务处理的时间很短而请求的数目却是巨大的 必然 会使用线程池
2.并发错误
线程池和其它排队机制依靠使用 wait() 和 notify() 方法,这两个方法都难于使用。如果编码不正确,那么可能丢失通知,导致线程保持空闲状态,尽管队列中有工作要处理。使用这些方法时,必须格外小心。而最好使用现有的、已经知道能工作的实现,例如 util.concurrent 包
常用的几种线程池
newCachedThreadPool newSingleThreadExecutor 数据库的连接池
#########################################
JVM基础 面试题 初级 有说可说
Jvm俗称Java虚拟机,他是java运行环境的一部分,它虚构出来的一台计算机,在通过在实际的计算机上仿真模拟各种计算机功能来实现Java应用程序
=========================================
说一说jvm有哪些区
有5个
最重要的是 运行时数据区 也就是我们常说的JVM内存.因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)
还有类加载模型 就是双亲委派模型
还有四大加载器
类的加载
回收机制
问题 1
jvm年轻代垃圾回收算法和老年代算法分别是什么
一般分配到新生代s0区域,每次被垃圾回收一次,标记加1,到达15次这个值可以用调整以后进入老年代 老年代满触发gc
问题 2
如说排除内存泄漏用你用什么工具
JProfiler
问题3
能不能解释一下方法区
方法区是所有线程共享的内存区域,它用于存储已被Java虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
它有个别命叫Non-Heap(非堆)。当方法区无法满足内存分配需求时,抛出OutOfMemoryError异常。
、
问题4
知道垃圾收集系统吗?
程序在运行过程中,会产生大量的内存垃圾(一些没有引用指向的内存对象都属于内存垃圾,因为这些对象已经无法访问,程序用不了它们了,对程序而言它们已经死亡),为了确保程序运行时的性能,java虚拟机在程序运行的过程中不断地进行自动的垃圾回收(GC)。
垃圾收集系统是Java的核心,也是不可少的,Java有一套自己进行垃圾清理的机制,开发人员无需手工清理
问题5
Java会存在内存泄漏吗?请说明为什么
Java是有GC垃圾回收机制的,也就是说,不再被使用的对象,会被GC自动回收掉,自动从内存中清除。
即使这样,Java也还是存在着内存泄漏的情况,java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景
=================================加油吧=!!!=