• 模拟线程饥饿


    思路和代码来自于网络,本文仅是个人记录性质,感谢原作者们。

    思路

    线程1、线程2来自于一个固定线程池newFixedThreadPool(2),然后分别都去执行任务A,任务A当中会向同一个线程池提交任务B返回Future,同时任务A使用Future.get()等待任务B的返回结果才能继续往下执行。
    于是会发生以下现象:线程1、2都在执行任务A,都向线程池提交了任务B、且都等各自的任务B结束,线程池只有2个线程现在都在执行任务A所以两个任务B进入阻塞队列等待,而只有当线程1、2执行完任务A才会释放回池里执行任务B,所以陷入一种类似死锁的场景,线程饥饿。

    /**
     * 模拟线程饥饿
     * */
    public class ThreadStarvingTest {
    	
    	public static void main(String[] args) {
    		ExecutorService executorService = Executors.newFixedThreadPool(2);
    		
    		executorService.submit(() -> {
    			System.out.println(currentThreadName() + "接待客人");
    			Future<String> cook = executorService.submit(() -> {
    				System.out.println(currentThreadName() + "做回锅肉");
    				return "回锅肉";
    			});
    
    			try {
    				System.out.println(currentThreadName() + "上" + cook.get()); //Waits if necessary for the computation to complete, and thenretrieves its result.
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			} catch (ExecutionException e) {
    				e.printStackTrace();
    			}
    		});
    
    		executorService.submit(() -> {
    			System.out.println(currentThreadName() + "接待客人");
    			Future<String> cook = executorService.submit(() -> {
    				System.out.println(currentThreadName() + "做鱼香肉丝");
    				return "鱼香肉丝";
    			});
    		
    			try {
    				System.out.println(currentThreadName() + "上" + cook.get());
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			} catch (ExecutionException e) {
    				e.printStackTrace();
    			}
    		});
    		
    	}
    	
    	public static String currentThreadName() {
    		return Thread.currentThread().getName();
    	}
    
    }
    

    返回结果:

    pool-1-thread-1接待客人
    pool-1-thread-2接待客人
    

    如果把fixed线程池大小改成3,就会执行下去了:

    pool-1-thread-1接待客人
    pool-1-thread-2接待客人
    pool-1-thread-3做回锅肉
    pool-1-thread-1上回锅肉
    pool-1-thread-3做鱼香肉丝
    pool-1-thread-2上鱼香肉丝
    

    线程的daemon属性

    上面我们会发现两种情况里,jvm进程最后都没结束,以往印象里main()这类hello world测试程序主线程跑完程序就退出结束了,或者是在之前搞过写死循环或者阻塞(比如SocketServer那类程序),然后程序一直执行。所以这里我们jstack可以看到main线程跑完了,那么jvm进程没结束,是因为线程池的两个线程还继续等待执行任务。
    我们只要把线程池里的线程都设置为daemon=true,那么就可以在main线程结束以后,也结束jvm进程了:

    实现一个ThreadFactory

    import java.util.concurrent.ThreadFactory;
    
    public class MyThreadFactory implements ThreadFactory{
    
    	@Override
    	public Thread newThread(Runnable r) {
    		Thread t = new Thread(r);
    		t.setDaemon(true);
    		return t;
    	}
    
    }
    

    然后用ThreadPoolExecutor自定义线程池替换Executors.newFixedThreadPoll:

    ExecutorService executorService = new ThreadPoolExecutor(3, 3, 0, //coreSize, maxSize, keepalivetime都是0
    							TimeUnit.SECONDS,
    							new LinkedBlockingQueue<Runnable>(), //任务队列也跟原来一样
    							new MyThreadFactory(), //用自定义的ThreadFactory
    							new AbortPolicy()); //拒绝策略也跟原来一样,用Abort
    

    执行结果:

    Thread-0接待客人
    Thread-1接待客人
    Thread-2做回锅肉
    Thread-0上回锅肉
    Thread-2做鱼香肉丝
    Thread-1上鱼香肉丝
    main主线程结束
    

    主线程结束了,它启动的线程池里边的线程又都是daemon线程,所以会随着主线成结束而结束,所以jvm进程也就结束了。

  • 相关阅读:
    下载文件乱码问题的解决
    Jquery Ajax实例(一)
    JQuery实现checkbox的全选/取消全选,实现类似于邮箱功能
    C#重写ToString方法实例
    生成不重复的随机数
    List<T>清除重复某一项
    Ubuntu16.04安装有道词典
    Ubuntu16.04 VTK7.1.0+QT4.8.6+QtCreator开发环境配置
    MATLAB求解代数方程、微分方程的一些常用指令
    读取Simulink中Dataset类型的数据
  • 原文地址:https://www.cnblogs.com/lyhero11/p/15544768.html
Copyright © 2020-2023  润新知