多线程基础知识总结

一.多线程:

1.1 线程的实现方式细节:

Thread类本质是实现了Runnable接口的一个实例,代表一个线程的实例。

启动方式是通过Thread类的start()方法,start()方法是一个native方法,启动一个心线程,并执行run方法

1.2 线程的生命周期:

生命周期为:新建,就绪,运行,阻塞,死亡

新建:当使用了new关键字创建了一个线程后。(此时JVM为其分配内存,并初始化其成员变量)

就绪:当线程对象调用了start()方法后。Java虚拟机会为其创建方法调用栈和程序计数器

运行:处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体。

阻塞:因为某种原因放弃了CPU的使用权。

​ 三种情况:等待阻塞,同步阻塞,其他阻塞

​ 等待阻塞:运行的线程执行wait方法

​ 同步阻塞:运行的线程在获得对象的同步锁时,若该同步锁被别的线程占用,则JVM会将其放入线程池

​ 其他阻塞:执行sleep()或者join()方法,或者发出了I/O请求时

死亡:

​ 三种情况----正常结束,异常结束,调用stop

​ 正常结束:run()或者call()方法执行完成,线程正常结束。

​ 异常结束:线程抛出一个未捕获的Exception 或Error

​ 调用stop: 调用该线程的stop方法,容易导致死锁

1.3 线程关键字Interrupt使用细节

使用interrupt()方法中短线程有两种情况:

1.3.1线程处于阻塞状态

当使用了sleep,同步锁的wait,socket中的receiver,accept等方法时,会时线程处于阻塞状态。

当调用线程的interrupt()方法时,会抛出InterruptException异常。

一定要捕获InterruptedException异常之后通过break跳出循环,才能正常结束run方法

1.3.2线程处于非阻塞状态

使用isInterrupted()判断线程的中断标志来推出循环。

1.3.3相关实现代码:

public class ThreadSafe extends Thread {
 	public void run() { 
        while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
            try{
                Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出
                catch(InterruptedException e){
                    e.printStackTrace();
                    break;//捕获到异常之后,执行 break 跳出循环
                }
            }
	} 
}

1.4 线程关键字比较:

1.4.1 sleep和wait的区别:

1.sleep()方法属于Thread类,wait()属于Object类

2.sleep()不释放对象锁,让出cpu给其他线程;

3.调用wait方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,需要调用notify()方法

1.4.2 start()和run()的区别

start()真正实现多线程的运行,此时线程处于就绪(可运行)状态,并没有运行,一旦得到时间片,里面的线程体run()方法就开始执行,其中包含了要执行的这个线程的内容

run()方法只是类的一个普通方法而已,直接调用run,程序依然只有主线程这一个线程,其程序执行路径还是只有一条,还要顺序执行,还要等待run方法体执行完毕后才可以继续执行下面的代码。

调用start方法实现多线程,而调用run方法没有实现多线程 (run没有另起线程,而start才是真正意义的新开线程)

1.5线程池的创建

线程池的顶级接口是Executor,但是其只是一个执行线程的工具,真正的线程池接口时ExecutorServer。

实现线程池的四种方式:

1.5.1 newCachedThreadPool

介绍:可缓存线程池,如果线程长度超过处理需要,可灵活回收空闲线程,若无可回收,则创建新的线程

创建代码:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
    try {
        Thread.sleep(index * 1000);
    } 
        catch (InterruptedException e) {
            e.printStackTrace();
    }

	cachedThreadPool.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println(index);
        }
	});
}
1.5.2 newFixedThreadPool

介绍:定长线程池,可控制线程最大并发数,超过的线程会在队列中等待

代码:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
    	final int index = i;
		fixedThreadPool.execute(new Runnable() {
			@Override
			public void run() {
                try {
                    System.out.println(index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
    			// TODO Auto-generated catch block
        			e.printStackTrace();
    			}
			}
	});
}
1.5.3 newScheduledThreadPool

介绍:定长线程池,支持定时及周期性任务执行。(安全,强大)

代码:

第一种(定时执行):延迟3秒执行。

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
 	scheduledThreadPool.schedule(new Runnable() {
		@Override
		public void run() {
    		System.out.println("delay 3 seconds");
		}
}, 3, TimeUnit.SECONDS);

第二种(定期执行):延迟1秒后每3秒执行一次。

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
	@Override
	public void run() {
    	System.out.println("delay 1 seconds, and excute every 3 seconds");
	}
}, 1, 3, TimeUnit.SECONDS);
1.5.4 newSingleThreadExecutor

介绍:单线程的线程池,之用唯一的工作线程来执行任务,保证按照FIFO,LIFO,优先级执行

代码:

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
	for (int i = 0; i < 10; i++) {
		final int index = i;
		singleThreadExecutor.execute(new Runnable() {
            @Override
            public void run() {
            	try {
            		System.out.println(index);
            		Thread.sleep(2000);
            	} catch (InterruptedException e) {
            		// TODO Auto-generated catch block
            		e.printStackTrace();
            	}
         	}
    	});
	}

1.6 线程池的七个参数:

1.6.1 corePoolSize:线程池核心线程大小

介绍:最小的线程数量,即使这些线程处于空闲状态,也不会销毁。除非设置AllowCoreThreadTimeOut,这里的最小线程数量即是corePoolSize

1.6.2 maximumPoolSize:线程池最大线程数量

介绍:一个任务被提交,首先会找空闲存活线程,如果有则直接奖任务交给这个空闲线程来执行,如果没有会缓存到队列中。如果队列满了,才会创建一个新的线程。线程池不会无限制的创建线程,会有一个最大线程数量maximumPoolSize

1.6.3 KeepAliveTime:空闲线程存活时间

介绍:一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后会被销毁

1.6.4 unit:空闲线程存活时间单位

介绍:略

1.6.5 workQueue:工作队列

介绍:新任务提交,会先进入任务队列,jdk提供了四种工作队列

​ ①ArrayBlockingQueue:基于数组的有界阻塞队列,按FIFO排序。新任务进来。放到队尾

​ ②LinkedBlockingQuene:基于链表的无界阻塞队列(其实最大容量为Integer.MAX),按照FIFO排序。不会创建新的线程,参数maxPoolSize不起作用

​ ③SynchronousQuene:一个不缓存任务的阻塞队列,生产者放入一个任务,必须等消费者取出这个任务。

​ ③SynchronousQuene:具有优先级的阻塞队列,优先级通过comparator实现

1.6.6 threadFactory线程工厂

介绍:创建一个新线程时使用的工厂,可以用来设定线程名,是否为daemon线程等等

1.6.7 handler拒绝策略

介绍:当工作队列的任务已经到达最大限制,并且线程池中的线程数量也达到了最大限制,就会采用拒绝策略

1.7 拒绝策略细节

策略1:ThreadPoolExecutor.AbortPolicy()

介绍:抛出java.util.concurrent.RejectedExecutionException异常

策略2:ThreadPoolExecutor.CallerRunsPolicy

介绍:用于被拒绝任务的处理程序,直接在execute方法中调用线程中运行被拒绝的任务。如果程序已关闭,则丢弃

策略3:ThreadPoolExecutor.DiscardPolicy

介绍:用于被拒绝的应用程序,默认情况下他将丢弃被拒绝的任务

策略4:ThreadPoolExecutor.DiscardOldestPolicy()

介绍:先进先出原则,丢弃最老的一个请求,并尝试再次提交任务

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值