java多线程
一、什么是线程?
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
二、线程和进程有什么区别?
线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。
不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。
别把它和栈内存搞混,每个线程都拥有单独的栈内存用来存储本地数据。
、线程的实现方式:
1.继承Thread类重写run方法
2.实现Runnable接口重写run方法
3.实现Callable重写call方法
4.使用线程池
线程池的作用:创建线程需要花费昂贵的资源和时间,如果任务来了再创建线程那么响应的时间会变长。
而且一个进程能创建的线程数量有限。
为了避免这样的问题在程序启动时就创建了若干线程来进行相应处理。
这就被称为线程池,java提供了Executor框架让你可以创建不同的线程池。
5种线程池
线程安全
所谓的线程安全问题,本质在于线程对共享变量的操作的原子性,可见性,有序性不能同时满足。
因此解决线程安全问题的关键在于使其同时满足以上三个特征
Java多线程中调用wait() 和 sleep()方法有什么不同?
Java程序中wait 和 sleep都会造成某种形式的暂停,它们可以满足不同的需要。
wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁;
他是object中的方法要和synchronized联合使用。
而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁,他是Thread类的方法。
线程的状态
a.新建{
继承Thread类创建线程
实现Runnable接口创建线程
使用Callable和Future创建线程
使用线程池例如用Executor框架
}
b.运行
c.阻塞{
同步阻塞
竞争锁失败
等待阻塞
调用wait,lockSupport.park()等方法
其他阻塞
}
d.就绪{
调用thread.start()
}
e.结束
f.线程运行完毕
如何避免死锁?
Java多线程中的死锁:
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象。
若无外力作用,它们都将无法推进下去。
这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:
a.互斥条件:一个资源每次只能被一个进程使用。
b.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
c.不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
d.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
线程中的常用方法:
1.start()与run()
start() 启动线程并执行相应的run()方法
run() 子线程要执行的代码放入run()方法
2.getName()和setName()
getName() 获取此线程的名字
setName() 设置此线程的名字
3.join()和yield()
yield() 暂停当前方法,释放自己拥有的CPU,线程进入就绪状态。
它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权;
但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;
也有可能是当前线程又进入到“运行状态”继续运行!yield方法也不会释放同步锁
join() 加入线程。
4.interrupt()
interrupt() 中断线程 由运行状态到死亡状态
5.setDaemon()
setDaemon(true) 设置当前线程为守护线程
6.getPriority()
getPriority() 获取线程优先级 1~10 默认值为5 优先级越高被优先调用的频率越高
7.notify 和 notifyAll
notify方法只唤醒一个等待(对象的)线程并使该线程开始执行。
所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程;
选择哪个线程取决于操作系统对多线程管理的实现。
notifyAll 会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现。
如果当前情况下有多个线程需要被唤醒,推荐使用notifyAll 方法。
比如在生产者-消费者里面的使用,每次都需要唤醒所有的消费者或是生产者--
以判断程序是否可以继续往下执行。
线程详解:线程详解