1.队列的概念
谈到多线程先讲下队列的概念,之后的多线程学习会用到此类知识。
队列分为:阻塞式队列(有界)、非阻塞式队列(无界),遵循着先进先出、后进后出的原则。
阻塞队列与非阻塞队列区别:
1.非阻塞式队列超出队列总数会丢失。
2.阻塞式队列超出总数会进入等待(等待时间=设置超时时间)。
3.获取队列方面:非阻塞式队列,如果为空返回null。阻塞式队列,如果为空也会进入等待。
非阻塞式队列ConcurrentLinkedDeque
1 //非阻塞式队列 无界(可以声明无限个队列)
2 public static void test1(){ 3
4 ConcurrentLinkedDeque<Object> objects = new ConcurrentLinkedDeque<>(); 5 objects.offer("java001"); 6 objects.offer("java002"); 7
8 System.out.println("队列总数:"+objects.size()); 9
10 //建议:获取队列之后删除
11 System.out.println("获取队列但不删除:"+objects.peek()); 12 System.out.println("获取队列但不删除,队列总数:"+objects.size()); 13 System.out.println("获取队列删除:"+objects.poll()); 14
15 //非阻塞式队列,如果为空返回null
16 System.out.println(objects.poll()); 17 System.out.println(objects.poll()); 18 System.out.println(objects.poll()); 19 System.out.println("获取队列删除,队列总数:"+objects.size()); 20 }
阻塞式队列ArrayBlockingQueue
1 //阻塞式队列
2 public static void test2() throws InterruptedException { 3
4 long startTime=System.currentTimeMillis(); 5 ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3); 6 arrayBlockingQueue.offer("A001",3, TimeUnit.SECONDS); 7 arrayBlockingQueue.offer("A002",3, TimeUnit.SECONDS); 8
9 //阻塞式队列超出总数等待(等待时间=设置超时时间)
10 arrayBlockingQueue.offer("A003",3, TimeUnit.SECONDS); 11 arrayBlockingQueue.offer("A004",1, TimeUnit.SECONDS); 12 arrayBlockingQueue.offer("A005",1, TimeUnit.SECONDS); 13
14 System.out.println("队列总数:"+arrayBlockingQueue.size()); 15 System.out.println(arrayBlockingQueue.poll()); 16 System.out.println(arrayBlockingQueue.poll()); 17 System.out.println(arrayBlockingQueue.poll()); 18 //阻塞式队列,如果为空也会等待。
19 System.out.println(arrayBlockingQueue.poll(1, TimeUnit.SECONDS)); 20 System.out.println("队列剩余总数:"+arrayBlockingQueue.size()); 21
22 System.out.println("耗时:"+ (System.currentTimeMillis() - startTime)/1000 +"秒"); 23
24 }
2.线程池
线程池好处:
1.降低资源 => 重复利用机制 (降低创建线程和销毁线程)
2.提高响应效率 => 当任务到达时,任务可以不需要等待去创建线程就可以执行
3.方便管理 => 无限创建线程消耗资源、降低系统稳定性。使用线程池可以统一分配、调优、监控。
线程与任务的区别:
可以把线程理解成一个工作人员。而任务就是这个工作人员干的活。比如,餐厅的工作人员在为顾客传菜,传菜就是个任务。
Java中线程就是Thread类或其子类的一个实例。
也就是说你不必关注线程对象是用哪种方法创建的。在此基础上,线程所执行的代码,即run方法中的代码所实现的处理逻辑,
比如读取数据库中的一条记录,就是一个任务。因此,所谓任务是一个相对的概念。一个任务可以是读取数据库中的一条记录,
也可以是FTP传输一批文件,FTP传输一个文件……
1 //创建线程四种方式: 2 //1.可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 3 //2.定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 4 //3.可定时线程池,支持定时及周期性任务执行。 5 //4.单例线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
6 public static void test1() { 7
8 //1.可缓存、定时、定长、单例
9 ExecutorService executorService = Executors.newCachedThreadPool(); 10 for (int i = 0; i <10 ; i++) { 11 final int i1 = i; 12 executorService.execute(new Runnable() { 13 @Override 14 public void run() { 15 System.out.println(Thread.currentThread().getName()+",i:"+ i1); 16 } 17 }); 18 } 19
20 } 21
22 public static void test2() { 23
24 //2.可定长线程,核心线程5个,最多创建5个线程 (只会创建5个线程,其他线程共享这5个线程)
25 ExecutorService executorService = Executors.newFixedThreadPool(5); 26 for (int i = 0; i <10 ; i++) { 27 final int i1 = i; 28 executorService.execute(new Runnable() { 29 @Override 30 public void run() { 31 System.out.println(Thread.currentThread().getName()+",i:"+ i1); 32 } 33 }); 34 } 35 } 36
37 public static void test3() { 38
39 long l = System.currentTimeMillis(); 40 //3.可定时线程 =>核心线程数3 (延迟三秒执行)
41 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); 42 for (int i = 0; i <10 ; i++) { 43
44 final int i1 = i; 45 scheduledExecutorService.schedule(new Runnable() { 46 @Override 47 public void run() { 48 System.out.println(Thread.currentThread().getName()+",i:"+ i1); 49 System.out.println("耗时:"+ (System.currentTimeMillis() -l)/1000 +"秒" ); 50 } 51 },3, TimeUnit.SECONDS); 52 } 53
54
55
56 } 57
58 public static void test4() { 59
60 //4.单例线程 =>核心线程数1 最大线程数1
61 ExecutorService executorService = Executors.newSingleThreadExecutor(); 62 for (int i = 0; i <10 ; i++) { 63 final int i1 = i; 64 executorService.execute(new Runnable() { 65 @Override 66 public void run() { 67 System.out.println(Thread.currentThread().getName()+",i:"+ i1); 68 } 69 }); 70 } 71 }