多线程
概念
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。
线程池
概念
线程池(thread pool)就是提前创建若干个线程,如果有任务需要处理,线程池里的线程就会处理任务,处理完之后线程并不会被销毁,而是等待下一个任务。由于创建和销毁线程都是消耗系统资源的,所以当你想要频繁的创建和销毁线程的时候就可以考虑使用线程池来提升系统的性能。
java 提供了一个 java.util.concurrent.Executor接口的实现用于创建线程池。
线程池的创建:
//核心线程数、最大线程数、存活时间,时间单位,队例类型
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
1. newCachedThreadPool创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
//newCachedThreadPool创建一个可缓存线程池
public class CachedThreadPool {
public static void main(String[] args) {
// TODO Auto-generated method stub
cachedThreadPool();
}
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
private static void cachedThreadPool(){
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
//我们在等执行下一线程的时候,在此等待1S,等前一个线程执行完成
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + "==>" + index);
}
});
System.out.println("当前线程池中线程数量"+((ThreadPoolExecutor)cachedThreadPool).getPoolSize());
}
}
}
2. newFixedThreadPool 创建
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
//newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数。
public class FixedThreadPool {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
//fixedThreadPool01();
//fixedThreadPool02();
fixedThreadPool03();
}
//1.当创建一个定长线程池时,无论线程池中的线程有没有执行完成,只要线程池没有到达最大数量,它都会创建一个新线程
private static void fixedThreadPool01() throws InterruptedException {
ExecutorService cachedThreadPool = Executors.newFixedThreadPool(10);
//当创建一个定长线程池时,无论线程池中的线程有没有执行完成,只要线程池没有到达最大数量,它都会创建一个新线程
for (int i = 0; i < 6; i++) {
final int index = i;
Thread.sleep(1000);
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + "==>" + index);
}
});
System.out.println("当前线程池中线程数量"+((ThreadPoolExecutor)cachedThreadPool).getPoolSize());
}
}
//2.当线程池的线程到达最大数量,如果有空闲线程就会使用空闲线程执行,如果没有空闲线程就会出现排队
private static void fixedThreadPool02() {
ExecutorService cachedThreadPool = Executors.newFixedThreadPool(5);
//当线程池的线程到达最大数量,如果有空闲线程就会使用空闲线程执行,如果没有空闲线程就会出现排队
for (int i = 0; i < 10; i++) {
final int index = i;
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + "==>" + index);
}
});
System.out.println("当前线程池中线程数量"+((ThreadPoolExecutor)cachedThreadPool).getPoolSize());
System.out.println("当前线程池中排队数量==》"+((ThreadPoolExecutor)cachedThreadPool).getQueue().size());
}
}
//3.当线程池的线程到达最大数量,如果有空闲线程就会使用空闲线程执行,如果没有空闲线程就会出现排队
private static void fixedThreadPool03() throws InterruptedException {
ExecutorService cachedThreadPool = Executors.newFixedThreadPool(5);
//当线程池的线程处于空闲状态,不会进行回收
for (int i = 0; i < 10; i++) {
final int index = i;
if(i>18){
Thread.sleep(1000 * 65);
}
cachedThreadPool.execute(new Runnable() {
public void run() {
//System.out.println(Thread.currentThread().getId() + "==>" + index);
}
});
System.out.println("当前线程池中线程数量"+((ThreadPoolExecutor)cachedThreadPool).getPoolSize());
System.out.println("当前线程池中排队数量==》"+((ThreadPoolExecutor)cachedThreadPool).getQueue().size());
}
}
}
3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
//newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
public class ScheduledThreadPool {
public static void main(String[] args) {
// TODO Auto-generated method stub
scheduledThreadPool01();
scheduledThreadPool02();
scheduledThreadPool03();
}
//延时执行
private static void scheduledThreadPool01(){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
for(int i=0;i<10;i++){
Long startTime = System.currentTimeMillis();
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("线程名称:" + Thread.currentThread().getName()
+ " 延时运行时间==>>" + (System.currentTimeMillis() - startTime));
}
}, 3, TimeUnit.SECONDS);
}
}
//延时后,当前任务没有执行完成,但是到达第二次执行时间,如果前一个任务没有执行完成时,此时会等待。等到前一个任务执行完成后,第二个任务马上执行。
private static void scheduledThreadPool02(){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
Long startTime = System.currentTimeMillis();
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("延时运行时间==>>" + (System.currentTimeMillis() - startTime));
try {
//当此处等待时间大于周期时间时,将以这个时间为执行间隔时间,因为有等待时间
//如此处时间小于间隔时间时,以间隔时间为准,这时没有等待时间
Thread.sleep(1000 * 4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 3,3, TimeUnit.SECONDS);
}
//scheduleWithFixedDelay 当前任务结束后再次等一个间隔时间再进行执行
private static void scheduledThreadPool03(){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
//当前任务结束后,再等待一个间隔时间(3s)执行下一个任务
Long startTime = System.currentTimeMillis();
scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
public void run() {
System.out.println("延时运行时间==>>" + (System.currentTimeMillis() - startTime));
try {
Thread.sleep(1000 * 4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 3,3, TimeUnit.SECONDS);
}
}
4. newSingleThreadExecutor
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
//newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务。
public class SingleThreadExecutor {
public static void main(String[] args) {
// TODO Auto-generated method stub
singleThread01();
}
//按顺序来执行线程任务 但是不同于单线程,这个线程池只是只能存在一个线程,这个线程死后另外一个线程会补上。这种方式相对简单就是创建一个线程,按顺序进行执行
private static void singleThread01() {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(Thread.currentThread().getId() + "==>>" + index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
线程池的优点?
- 重用存在的线程,减少对象创建销毁的开销。
- 可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
- 提供定时执行、定期执行、单线程、并发数控制等功能。
死锁
概念
死锁(Deadlock)是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务。
死锁发生条件
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
怎么检测一个线程是否拥有锁?
在java.lang.Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。