zoukankan      html  css  js  c++  java
  • 第11章 进程与多线程

      1 /*****************
      2 ***第11章 进程与多线程
      3 *******知识点:
      4 **************1.进程和线程的概念与原理
      5 ******************1.1 进程
      6 ******************1.2 线程
      7 **************2.线程的创建和启动
      8 ******************2.1 定义线程
      9 ******************2.2 实例化线程
     10 ******************2.3 应用
     11 **************3.线程栈模型与线程的变量
     12 **************4.状态转换
     13 ******************4.1 五大状态
     14 ******************4.2 生命周期
     15 ******************4.3 状态关键字
     16 **************5.同步和锁
     17 ******************5.1 同步方法
     18 ******************5.2 同步块
     19 ******************5.3 生产者消费者模型
     20 ******************5.4 死锁
     21 ******************5.5 volatile关键字
     22 **************6.交互
     23 ******************6.1 交互关键字
     24 **************7.调度
     25 ******************7.1 休眠
     26 ******************7.2 优先级
     27 ******************7.3 让步
     28 ******************7.4 合并
     29 ******************7.5 守护线程
     30 **************8.新特征
     31 ******************8.1 线程池
     32 ******************8.2 有返回值的线程
     33 ******************8.3 锁调度
     34 ******************8.4 信号量
     35 ******************8.5 阻塞队列
     36 ******************8.6 阻塞栈
     37 ******************8.7 条件变量
     38 ******************8.8 原子量
     39 ******************8.9 障碍器
     40 */
     41 
     42 import java.util.*;
     43 import java.util.concurrent.*;  //新特性包
     44 
     45 /*
     46 *继承Thread 演示线程类
     47 */
     48 class MyThreadTest1 extends Thread{
     49     private String name;
     50     public MyThreadTest1(){
     51         super("无名氏");
     52         this.name = "无名氏";    
     53     }
     54     public MyThreadTest1(String name){
     55         super(name);
     56         this.name = name;
     57         
     58     }
     59     public void run(){
     60         for(int i = 0 ; i < 10; i++){
     61             System.out.println("线程类:" + this.getClass() + "——线程对象:" + name + "——打印出来:" + i);
     62             if(i % 3 == 0){
     63                 try{
     64                     System.out.println("能整除3,我要休息一下!");
     65                     Thread.sleep(1000);//睡眠1000毫秒  即1秒
     66                 }catch(InterruptedException e){
     67                     System.out.println("线程异常!");
     68                 }
     69             }
     70         }
     71     }
     72     
     73 }
     74 
     75 /*
     76 *实现Runnable接口 演示线程类
     77 */
     78 class MyThreadTest2 implements Runnable{
     79     private String name;
     80     public MyThreadTest2(){
     81         this.name = "无名氏";
     82     }
     83     
     84     public MyThreadTest2(String name){
     85         this.name = name;
     86     }
     87     
     88     public void run(){
     89         for(int i = 0 ; i < 10; i++){
     90             System.out.println("线程类:" + this.getClass() + "——线程对象:" + name + "——打印出来:" + i);
     91         }
     92     }
     93 }
     94 
     95 /*
     96 *演示线程池类
     97 */
     98 class testPool extends Thread{
     99     public void run(){
    100         System.out.println(Thread.currentThread().getName() + "正在运行.....");
    101     }
    102 }
    103 
    104 /*
    105 *主任务类
    106 */
    107 class MainTask implements Runnable{
    108     public void run(){
    109         System.out.println("主任务运行.....");
    110     }
    111 }
    112 
    113 /*
    114 *子任务类
    115 */
    116 class SubTask implements Runnable{
    117     private String name;
    118     private CyclicBarrier cb; //主任务障碍器
    119     
    120     public SubTask(String name,CyclicBarrier cb){
    121         this.name = name;
    122         this.cb = cb;
    123     }
    124     
    125     public void run(){
    126         System.out.println("子任务" + name + "开始运行.....");
    127         for(int i = 0; i < 500000; i++){
    128             
    129         }
    130         System.out.println("子任务" + name + "完成运行");
    131         try{
    132             cb.await();  //设置障碍器等待状态
    133         }catch(InterruptedException e){
    134               e.printStackTrace(); 
    135         }catch(BrokenBarrierException e){
    136               e.printStackTrace(); 
    137         }
    138     }
    139         
    140 }
    141 
    142 public class test11{
    143     public static void main(String[] args){
    144         demoBaseInfo();//演示1.进程和线程的概念与原理
    145         demoCreateThread();//演示2.线程的创建和启动
    146         demoThreadStack();//演示3.线程栈模型与线程的变量
    147         demoThreadState();//演示4.状态转换
    148         demoSynchronizeAndLock();//演示5.同步和锁
    149         demoThreadInteraction();//演示6.交互
    150         demoThreadDispatch();//演示7.调度
    151         demoThreadNewFeatures();//演示8.新特征
    152     }
    153     
    154     /*
    155     *1.进程和线程的概念与原理
    156     */
    157     public static void demoBaseInfo(){
    158         /**1.1进程**/
    159         //进程:一个内存中运行的应用程序,拥有自己独立的一块内存空间,一个进程中可以有多个线程
    160         
    161         /**1.2线程**/
    162         //线程:进程中的一段执行流程。一个进程中的多个线程共享进程中的内存数据(所以可以理解线程是轻量级的进程)
    163     }
    164     
    165     /*
    166     *2.线程的创建和启动
    167     */
    168     public static void demoCreateThread(){
    169         //两种方式创建进程
    170         //1.继承Thread类 重写run方法
    171         //2.实现Runnable接口  重写run方法
    172         Thread mythread1 = new MyThreadTest1();//通过继承线程类创建实例
    173         
    174         Thread mythread2 = new Thread(new MyThreadTest2("ciade"));//通过实现接口创建实例  注意与第一种方式的区别
    175         
    176         System.out.println(Thread.currentThread());//Thread.currentThread()返回当前执行的线程对象
    177         
    178         mythread1.start();    //只有调用了start()方法后,线程才能从新建状态移动到可运行状态
    179         mythread2.start(); //只有调用了start()方法后,线程才能从新建状态移动到可运行状态
    180         
    181         
    182     }
    183     
    184     /*
    185     *3.线程栈模型与线程的变量
    186     */
    187     public static void demoThreadStack(){
    188         //单不使用线程时,虚拟机中的调用栈应该是main()->main()的调用的方法1->main()的调用的方法2
    189         
    190         //使用线程时,当程序执行到start()方法时,会在原来栈上多出一个分支(可称为栈B 之前的栈为栈A),两条线并行执行
    191         
    192         //理解即可  可配合画图说明
    193     }
    194     
    195     /*
    196     *4.状态转换
    197     */
    198     public static void demoThreadState(){
    199         /**4.1 五大状态**/
    200         //1.新建状态:线程对象已经定义声明并初始化,还没调用start()之前
    201         //2.可运行状态: 调用start()
    202         //3.运行状态:选择一个线程作为当前运行线程
    203         //4.等待/阻塞/睡眠状态:线程还是活的,只是没有条件运行而已
    204         //5.死亡状态:调用run()方法完成后的状态。注意如果在一个死去的线程上调用start()方法会出现异常
    205         
    206         /**4.2 生命周期**/
    207         //新建(new)->可运行(start)->运行(run)->死亡(run结束)
    208         //(其中运行状态可以变成等待/阻塞/睡眠状态(sleep),再变成可运行状态 ,如此循环)
    209         //可配合画图理解
    210         
    211         /**4.3 状态关键字**/
    212         //1.sleep关键字——————强制当前正在执行的线程休眠  
    213         //    使用方式:Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)
    214         //    注意事项:
    215         //            1.线程睡眠是帮助所有线程获得运行机会的最好办法
    216         //            2.线程睡眠到期自动苏醒,并返回到可运行状态,注意不是运行状态。
    217         //            3.sleep()中指定的是时间是线程不会运行的最小时间,所以不能保证该线程睡眠到期后就开始运行
    218         //            4.sleep()是静态方法,只能控制当前正在运行的线程
    219         //            5.sleep()时有可能出现InterruptedException异常  注意try..catch
    220         
    221         //2.yield关键字———————让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会
    222         //    使用方式:Thread.yield()
    223         //    注意事项:
    224         //            1.yield()从未导致线程转到等待/睡眠/阻塞状态
    225         //            2.在大多数情况下,yield()将导致线程从运行状态转到可运行状态
    226         //            3.实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中
    227         //所以这个关键字是然并卵
    228         
    229         //3.线程的优先级
    230         //线程总是存在优先级,优先级范围在1~10之间。JVM线程调度程序是基于优先级的抢先调度机制。
    231         //在大多数情况下,当前运行的线程优先级将大于或等于线程池中任何线程的优先级。但这仅仅是大多数情况。
    232         
    233         //设置优先级————————线程对象调用setPriority(int Priority)方法  其中Priority参数取值范围:1~10
    234         //获取线程优先级——————线程对象调用getPriority()方法
    235         //线程类优先级静态常量——————MAX_PRIORITY(最大) 、MIN_PRIORITY(最小)、NORM_PRIORITY(默认为5)
    236         
    237         //4.join关键字——————让一个B线程加入到另一个A线程的尾部。即A执行完毕之前,B不能工作.
    238         //                    线程的加入join()对线程栈导致的结果是线程栈发生了变化,当然这些变化都是瞬时的
    239         //5.interrupt关键字——————通知该线程中止,当改线程进行到阻塞状态时(sleep等),才会退出线程
    240         //6.stop关键字——————强行退出线程,有可能导致异常发生,所以不建议使用该方法
    241         
    242     }
    243     
    244     /*
    245     *5.同步和锁
    246     */
    247     public static void demoSynchronizeAndLock(){
    248         //同步:是保证多线程安全访问竞争资源的一种手段
    249         //同步方法:
    250         /*
    251         (1)wait() / notify()方法
    252         (2)await() / signal()方法
    253         (3)BlockingQueue阻塞队列方法
    254         (4)PipedInputStream / PipedOutputStream
    255           第四种暂不说明
    256         */
    257         //锁:Java中每个对象都有一个内置锁
    258         /*
    259         关于锁和同步,有一下几个要点:
    260             1)、只能同步方法,而不能同步变量和类;
    261             2)、每个对象只有一个锁;当提到同步时,应该清楚在什么上同步?也就是说,在哪个对象上同步?
    262             3)、不必同步类中所有的方法,类可以同时拥有同步和非同步方法。
    263             4)、如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。
    264                 也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。
    265             5)、如果线程拥有同步和非同步方法,则非同步方法可以被多个线程自由访问而不受锁的限制。
    266             6)、线程睡眠时,它所持的任何锁都不会释放。
    267             7)、线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。
    268             8)、同步损害并发性,应该尽可能缩小同步范围。同步不但可以同步整个方法,还可以同步方法中一部分代码块。
    269             9)、在使用同步代码块时候,应该指定在哪个对象上同步,也就是说要获取哪个对象的锁。
    270         */
    271         
    272         /*
    273         线程同步小结
    274             1、线程同步的目的是为了保护多个线程反问一个资源时对资源的破坏。
    275             2、线程同步方法是通过锁来实现,每个对象都有切仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。
    276             3、对于静态同步方法,锁是针对这个类的,锁对象是该类的Class对象。静态和非静态方法的锁互不干预。一个线程获得锁,当在一个同步方法中访问另外对象上的同步方法时,会获取这两个对象锁。
    277             4、对于同步,要时刻清醒在哪个对象上同步,这是关键。
    278             5、编写线程安全的类,需要时刻注意对多个线程竞争访问资源的逻辑和安全做出正确的判断,对“原子”操作做出分析,并保证原子操作期间别的线程无法访问竞争资源。
    279             6、当多个线程等待一个对象锁时,没有获取到锁的线程将发生阻塞。
    280             7、死锁是线程间相互等待锁锁造成的,在实际中发生的概率非常的小。真让你写个死锁程序,不一定好使,呵呵。但是,一旦程序发生死锁,程序将死掉。
    281         */
    282         
    283         
    284     /**5.1 同步方法**/
    285     /*
    286     class TicketSource implements Runnable{
    287     private int ticket = 50;
    288     public void run(){
    289         for(int i = 1 ; i < 50; i++){    
    290                 try{
    291                     Thread.sleep(100);
    292                 }catch(InterruptedException e){
    293                     e.printStackTrace();
    294                 }
    295                 sale();
    296         }
    297     }
    298     
    299     public synchronized void sale(){  //同步方法
    300         if(ticket > 0){
    301             System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
    302         }
    303     }
    304     public static void main(String[] args){
    305         TicketSource  mt = new TicketSource();
    306         new Thread(mt,"000").start();
    307         new Thread(mt,"001").start();
    308         new Thread(mt,"002").start();
    309     
    310     
    311     }*/
    312     /**5.2 同步块**/
    313     /*
    314     class TicketSouce implements Runnable
    315     {
    316         //票的总数
    317         private int ticket=10;
    318         public void run()
    319         {
    320             for(int i=1;i<50;i++)
    321             {
    322                 synchronized(this){//同步块  注意位置  不能放在if后面
    323                     if(ticket>0)
    324                     {
    325                         //休眠1s秒中,为了使效果更明显,否则可能出不了效果
    326                         try {
    327                             Thread.sleep(1000);
    328                         } catch (InterruptedException e) {
    329                             e.printStackTrace();
    330                         }
    331                         System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
    332                     }
    333                                   }
    334             }
    335         }
    336     }
    337     */
    338     
    339     //总结:在使用同步块的时候一定要清楚同步块的位置,因此推荐使用同步方法
    340     
    341     /**5.3 生产者消费者模型**/
    342     /*对于此模型,应该明确一下几点:
    343     1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
    344     2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
    345     3、当消费者发现仓储没产品可消费时候会通知生产者生产。
    346     4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
    347     */
    348     
    349     /*三种实现方式*/
    350     
    351     /*1.wait()/notifyAll()方式
    352     //仓库类
    353     class Storge{
    354         private final int MAX_SIZE = 100;
    355         private LinkedList<Object> list = new LinkedList<Object>();
    356         
    357         public int getMAX_SIZE(){
    358             return MAX_SIZE;
    359         }
    360         
    361         public void setList(LinkedList<Object> list){
    362             this.list = list;
    363         }
    364         
    365         public LinkedList<Object> getList(){
    366             return list;
    367         }
    368         public Storge(){
    369             
    370         }
    371         
    372         //生产方法
    373         public void produce(int num,String name){
    374             synchronized(list){
    375                 while(list.size() + num > MAX_SIZE ){ //判断会不会满仓溢出
    376                     System.out.println("要生产的产品数量:" + num + " 库存量:" 
    377                                         + list.size() + "  " + name +"暂时不能执行生产任务");
    378                     try{
    379                         list.wait();//设置阻塞状态
    380                     }catch(InterruptedException e){
    381                         e.printStackTrace();
    382                     }
    383                 }
    384                 for(int i = 1; i <= num ;i++){
    385                     list.add(new Object());//生产
    386                 }
    387                 System.out.println(name + "已经生产了产品数量:" + num + " 库存量现在为:" + list.size());
    388                 list.notifyAll();//唤醒其他等待线程
    389             }
    390             
    391         }
    392         
    393         //消费方法
    394         public void  consume(int num,String name){
    395             synchronized(list){
    396                 while(num > list.size() ){//判断有没可消费的库存
    397                     System.out.println("要消费的产品数量:" + num + " 库存量:" 
    398                                         + list.size() + "  " + name +"暂时不能执行消费任务");
    399                     try{
    400                         list.wait();//设置阻塞状态
    401                     }catch(InterruptedException e){
    402                         e.printStackTrace();
    403                     }
    404                         
    405                 }
    406                 for(int i = 1; i <= num ;i++){
    407                     list.remove();//移除消费项
    408                 }
    409                 System.out.println(name + "已经消费了产品数量:" + num + " 库存量现在为:" + list.size());
    410                 list.notifyAll();//唤醒其他等待线程
    411             }
    412             
    413         }
    414         
    415     }
    416 
    417     //生产类
    418     class Producer extends Thread{
    419         private int num; //每次生产的数量
    420         private Storge storge;
    421         private String name;
    422         
    423         public Producer(int num,Storge storge,String name){
    424             this.num = num;
    425             this.storge = storge;
    426             this.name = name;
    427         }
    428         
    429         public void run(){
    430             produce(num,name);        
    431         }
    432         public void produce(int num ,String name){
    433             storge.produce(num,name);
    434         }
    435     }
    436 
    437 
    438     //消费类
    439     class Consumer extends Thread{
    440         private int num ; //设置每次消费数目
    441         private Storge storge; //设置仓库
    442         private String name;
    443         
    444         public Consumer(int num,Storge storge,String name){
    445             this.num = num;
    446             this.storge = storge;
    447             this.name = name;
    448         }
    449         
    450         
    451         public void run(){
    452             consume(num,name);    
    453         }
    454         
    455         public void consume(int num,String name){
    456             storge.consume(num,name);
    457         }
    458         
    459         main()方法中
    460         //仓库对象
    461         Storge storge = new Storge();
    462         
    463         //生产对象
    464         Producer p1 = new Producer(20,storge,"p1");
    465         Producer p2 = new Producer(30,storge,"p2");
    466         Producer p3 = new Producer(50,storge,"p3");
    467         Producer p4 = new Producer(10,storge,"p4");
    468         Producer p5 = new Producer(10,storge,"p5");
    469         Producer p6 = new Producer(80,storge,"p6");
    470         
    471         
    472         //消费对象
    473         Consumer c1 = new Consumer(50,storge,"c1");
    474         Consumer c2 = new Consumer(20,storge,"c2");
    475         Consumer c3 = new Consumer(30,storge,"c3");
    476         
    477     }*/
    478     
    479     /*2.await() / signal()方式(可取代第一种方式)
    480     第一步:引入相关包
    481     import java.util.concurrent.locks.Condition;  
    482     import java.util.concurrent.locks.Lock;  
    483     import java.util.concurrent.locks.ReentrantLock;
    484     
    485     第二步:重写仓库类
    486     class Storge{
    487         private final int MAX_SIZE = 100;
    488         private LinkedList<Object> list = new LinkedList<Object>();
    489         private final Lock lock = new ReentrantLock();  //添加锁对象
    490         private final Condition full = lock.newCondition();//添加条件1
    491         private final Condition empty = lock.newCondition();//添加条件2
    492         
    493         public int getMAX_SIZE(){
    494             return MAX_SIZE;
    495         }
    496         
    497         public void setList(LinkedList<Object> list){
    498             this.list = list;
    499         }
    500         
    501         public LinkedList<Object> getList(){
    502             return list;
    503         }
    504         public Storge(){
    505             
    506         }
    507         
    508         //生产
    509         public void produce(int num,String name){
    510             lock.lock();//加锁
    511                 while(list.size() + num > MAX_SIZE ){ //判断会不会满仓溢出
    512                     System.out.println("要生产的产品数量:" + num + " 库存量:" 
    513                                         + list.size() + "  " + name +"暂时不能执行生产任务");
    514                     try{
    515                         full.await();//设置生产阻塞状态  
    516                     }catch(InterruptedException e){
    517                         e.printStackTrace();
    518                     }
    519                 }
    520                 for(int i = 1; i <= num ;i++){
    521                     list.add(new Object());//生产
    522                 }
    523                 System.out.println(name + "已经生产了产品数量:" + num + " 库存量现在为:" + list.size());
    524                 full.signalAll();//唤醒其他等待线程
    525                 empty.signalAll();
    526                 lock.unlock(); //解锁
    527             
    528         }
    529         
    530         //消费
    531         public void  consume(int num,String name){
    532             lock.lock();//加锁
    533                 while(num > list.size() ){//判断有没可消费的库存
    534                     System.out.println("要消费的产品数量:" + num + " 库存量:" 
    535                                         + list.size() + "  " + name +"暂时不能执行消费任务");
    536                     try{
    537                         empty.await();//设置消费阻塞状态
    538                     }catch(InterruptedException e){
    539                         e.printStackTrace();
    540                     }
    541                         
    542                 }
    543                 for(int i = 1; i <= num ;i++){
    544                     list.remove();//移除消费项
    545                 }
    546                 System.out.println(name + "已经消费了产品数量:" + num + " 库存量现在为:" + list.size());
    547                 full.signalAll();//唤醒其他等待线程
    548                 empty.signalAll();
    549                 lock.unlock(); //解锁
    550             
    551         }
    552         
    553     }
    554     
    555     其他跟第一种方式一样 (达到无需修改main()方法中相关代码和消费类、生产类即可实现)
    556     //推荐以后使用此方式实现同步
    557     */
    558     
    559     /*3.BlockingQueue阻塞队列方式
    560     第一步:引入相关包
    561     import java.util.concurrent.LinkedBlockingQueue; 
    562     第二步:重写仓库类
    563     class Storge{
    564         private final int MAX_SIZE = 100;
    565         private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<Object>();//定义一个可同步的list
    566         
    567         public int getMAX_SIZE(){
    568             return MAX_SIZE;
    569         }
    570         
    571         public void setList(LinkedBlockingQueue<Object> list){
    572             this.list = list;
    573         }
    574         
    575         public LinkedBlockingQueue<Object> getList(){
    576             return list;
    577         }
    578         public Storge(){
    579             
    580         }
    581         
    582         //生产
    583         public void produce(int num,String name){
    584             if(list.size() + num > MAX_SIZE ){ //判断会不会满仓溢出
    585                     System.out.println("要生产的产品数量:" + num + " 库存量:" 
    586                                         + list.size() + "  " + name +"暂时不能执行生产任务");
    587                     
    588                 }
    589                 for(int i = 1; i <= num ;i++){
    590                     try{
    591                         list.put(new Object());//生产
    592                     }catch(InterruptedException e){
    593                         e.printStackTrace(); 
    594                     }
    595                     System.out.println(name + "已经生产了产品数量:" + num + " 库存量现在为:" + list.size());
    596                 }
    597                 
    598             
    599         }
    600         
    601         //消费
    602         public void  consume(int num,String name){
    603             
    604             if(num > list.size() ){//判断有没可消费的库存
    605                 System.out.println("要消费的产品数量:" + num + " 库存量:" 
    606                                 + list.size() + "  " + name +"暂时不能执行消费任务");
    607                 }
    608             for(int i = 1; i <= num ;i++){
    609                 try{
    610                     list.take();//移除消费项
    611                 }catch(InterruptedException e){
    612                     e.printStackTrace();
    613                 }
    614                 System.out.println(name + "已经消费了产品数量:" + num + " 库存量现在为:" + list.size());    
    615             }    
    616         }
    617         
    618     }
    619     其他跟第一种方式一样 (达到无需修改main()方法中相关代码和消费类、生产类即可实现)
    620     但可能会出现put跟打印出来的结果不一样。
    621     */
    622     
    623     //总结:推荐使用第二种方式实现同步
    624     
    625     /**5.4 死锁**/
    626     //发生死锁的原因一般是两个对象的锁相互等待造成的
    627     
    628     /***5.5 volatile关键字**/
    629     //Java包含两种内在的同步机制:同步块(或方法)和 volatile变量。这两种机制的提出都是为了实现代码线程的安全性。
    630     //其中 Volatile变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。所以你可以忘了它了
    631     }
    632     
    633     /*
    634     *6.交互
    635     */
    636     public static void demoThreadInteraction(){
    637         /**6.1 交互关键字**/
    638         //notify关键字:唤醒在此对象监视器上等待的单个线程
    639         //notifyAll关键字:唤醒在此对象监视器上等待的所有线程
    640         //wait关键字:导致当前的线程等待,直到其他线程调用此对象的notify()方法或者notifyAll()方法
    641         //其中wait()方法有两个重载的方法:
    642         //    1.void wait(long timeout)————导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者超过指定的时间量。
    643         //    2.void wait(long timeout, int nanos) —————导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
    644     
    645     }
    646     
    647     /*
    648     *7.调度
    649     */
    650     public static void demoThreadDispatch(){
    651         /**7.1 休眠**/
    652         //休眠目的————————使线程让出CPU的最简单的做法之一,线程休眠时候,会将CPU资源交给其他线程,以便能轮换执行,当休眠一定时间后,线程会苏醒,进入准备状态等待执行
    653         //实现方式:Thread.sleep(long millis)和Thread.sleep(long millis, int nanos),均为静态方法,谁调用就休眠谁
    654         
    655         /**7.2 优先级**/
    656         //优先级高的线程获取CPU资源的概率较大
    657         //优先级用1-10之间的整数表示,默认为5
    658         //一般情况下,子线程优先级跟父线程一致
    659         
    660         /**7.3 让步**/
    661         //让步——————使当前运行着线程让出CPU资源,但是然给谁不知道,仅仅是让出,线程状态回到可运行状态。
    662         //实现方式:Thread.yield()方法,yield()为静态方法,功能是暂停当前正在执行的线程对象,并执行其他线程。
    663         
    664         /**7.4 合并**/
    665         //合并——————将几个并行线程的线程合并为一个单线程执行,应用场景是当一个线程必须等待另一个线程执行完毕才能执行
    666         //实现方式:调用join()方法  非静态方法
    667         //其中join方法重载方法有:
    668         //        1.void join()  等待该线程终止。    
    669         //        2.void join(long millis)  等待该线程终止的时间最长为 millis毫秒。    
    670         //        3.void join(long millis,int nanos) 等待该线程终止的时间最长为 millis毫秒 + nanos 纳秒。
    671         
    672         /**7.5 守护线程**/
    673         //守护线程———————为其他线程的运行提供服务
    674         //实现方式:线程对象的方法setDaemon(true),则可以将其设置为守护线程
    675         //注意:
    676         //    1.调用setDaemon()必须在start()方法前
    677         //    2.Daemon线程中产生的新线程也是Daemon的
    678         //    3.不是所有的应用都可以分配给Daemon线程来进行服务(因为有可能线程还没来得及进行操作时,虚拟机就已经退出了)
    679         
    680     }
    681     
    682     /*
    683     *8.新特征
    684     */
    685     public static void demoThreadNewFeatures(){
    686         //新特性指的是在Java6及之后版本所拥有线程相关的新特性
    687         /**8.1 线程池**/
    688         //线程池分好多种:固定尺寸的线程池、单任务线程池、可变尺寸连接池、延迟连接池、自定义线程池等
    689         ExecutorService pool_1 = Executors.newFixedThreadPool(3);//创建一个固定可重用的线程池 容量为3
    690         ExecutorService  pool_2 =  Executors.newSingleThreadExecutor();//创建一个单任务线程池
    691         ExecutorService pool_3 =  Executors.newCachedThreadPool();//创建一个可变尺寸的线程池 
    692         ScheduledExecutorService  pool_4 =  Executors.newScheduledThreadPool(4);//创建一个延迟线程池
    693         
    694         Thread t1 = new testPool();
    695         Thread t2 = new testPool();
    696         Thread t3 = new testPool();
    697         Thread t4 = new testPool();
    698         
    699         
    700         System.out.println("固定可重用的线程池演示!");
    701         //将线程放入线程池中执行
    702         pool_1.execute(t1);
    703         pool_1.execute(t2);
    704         pool_1.execute(t3);
    705         pool_1.execute(t4);
    706         pool_1.shutdown();//关闭
    707         
    708         System.out.println("单任务线程池演示!");
    709         pool_2.execute(t1);
    710         pool_2.execute(t2);
    711         pool_2.execute(t3);
    712         pool_2.shutdown();//关闭
    713         
    714         System.out.println("可变尺寸线程池演示!");
    715         pool_3.execute(t1);
    716         pool_3.execute(t2);
    717         pool_3.execute(t3);
    718         pool_3.shutdown();//关闭*/
    719         
    720         System.out.println("延迟线程池演示!");
    721         pool_4.execute(t1);
    722         pool_4.execute(t2);
    723         
    724          //使用延迟执行风格的方法
    725          //第一个参数是延迟执行线程对象,第二个参数是延迟数量,第三个参数是延迟的单位
    726         pool_4.schedule(t3, 1000, TimeUnit.MILLISECONDS); //t3 延迟 1000毫秒
    727         pool_4.schedule(t4, 10, TimeUnit.SECONDS); //t4 延迟 10秒
    728         pool_4.shutdown();//关闭
    729         
    730         /**8.2 有返回值的线程**/
    731         //可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口(Thread类也实现Runnable接口)
    732         //实现方式:执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了
    733         /*
    734         
    735         class MyCallable implements Callable{
    736             private String oid;
    737 
    738             MyCallable(String oid) { 
    739                     this.oid = oid;
    740             } 
    741 
    742             @Override 
    743             public Object call()throws Exception {
    744                     return oid+"任务返回的内容";
    745             }
    746         }
    747         
    748         public static void main(String[] args)throws ExecutionException, InterruptedException {
    749                 //创建一个线程池
    750                 ExecutorService pool = Executors.newFixedThreadPool(2); 
    751                 
    752                 //创建两个有返回值的任务
    753                 Callable c1 = new MyCallable("A");
    754                 Callable c2 = new MyCallable("B");
    755                 
    756                 //执行任务并获取Future对象
    757                 Future f1 = pool.submit(c1); 
    758                 Future f2 = pool.submit(c2); 
    759                 
    760                 //从Future对象上获取任务的返回值,并输出到控制台
    761                 System.out.println(">>>"+f1.get().toString());
    762                 System.out.println(">>>"+f2.get().toString());
    763                 
    764                 //关闭线程池
    765                 pool.shutdown(); 
    766         } 
    767         
    768         //更多使用详见API文档
    769         */
    770         
    771         /**8.3 锁**/
    772         /**具体使用参考本文上面的生产者和消费者模型的第二种实现方式**/
    773         
    774         /**8.4 信号量**/
    775         /*
    776         信号量实际上是一个功能完毕的计数器,对控制一定资源的消费与回收有着很重要的意义,信号量常常用于多线程的代码中,
    777               并能监控有多少数目的线程等待获取资源,并且通过信号量可以得知可用资源的数目等等,这里总是在强调“数目”二字,
    778               但不能指出来有哪些在等待,哪些资源可用。
    779         貌似用处不大,使用的时候再查看相关文档即可
    780         */
    781         
    782         /**8.5 阻塞队列**/
    783         /**具体使用参考本文上面的生产者和消费者模型的第三种实现方式**/
    784         
    785         /**8.6 阻塞栈**/
    786         /**用法与阻塞队列相似,不同的是栈是后入先出的结构,每次操作都是栈顶元素,而队列则是先进先出结构,每次操作都是队头**/
    787         
    788         /**8.7 条件变量**/
    789         /**具体使用参考本文上面的生产者和消费者模型的第二种实现方式**/
    790         
    791         /**8.8 原子量**/
    792         //原子量:操作变量的操作是原子的,不可再分
    793         /*
    794         class MyRunnable implements Runnable {
    795             privatestatic AtomicLong aLong =new AtomicLong(10000);        //原子量,每个线程都可以自由操作
    796             private String name;                //操作人
    797             privateint x;                            //操作数额
    798             private Lock lock;
    799 
    800             MyRunnable(String name, int x,Lock lock) {
    801                     this.name = name;
    802                     this.x = x;
    803                     this.lock = lock;
    804             } 
    805 
    806             publicvoid run() {
    807                     lock.lock(); 
    808                     System.out.println(name + "执行了" + x +",当前余额:" + aLong.addAndGet(x));
    809                     lock.unlock(); 
    810         } 
    811         
    812          public static void main(String[] args) {
    813                 ExecutorService pool = Executors.newFixedThreadPool(2); 
    814                 Lock lock = new ReentrantLock(false);
    815                 Runnable t1 = new MyRunnable("张三", 2000,lock);
    816                 Runnable t2 = new MyRunnable("李四", 3600,lock);
    817                 Runnable t3 = new MyRunnable("王五", 2700,lock);
    818                 Runnable t4 = new MyRunnable("老张", 600,lock);
    819                 Runnable t5 = new MyRunnable("老牛", 1300,lock);
    820                 Runnable t6 = new MyRunnable("胖子", 800,lock);
    821                 //执行各个线程
    822                 pool.execute(t1); 
    823                 pool.execute(t2); 
    824                 pool.execute(t3); 
    825                 pool.execute(t4); 
    826                 pool.execute(t5); 
    827                 pool.execute(t6); 
    828                 //关闭线程池
    829                 pool.shutdown(); 
    830         } 
    831         
    832         */
    833         /**8.9 障碍器**/
    834         //障碍器是多线程并发控制的一种手段。
    835         //应用场景:如果一个主干任何中有许多子任务需要执行,那么只有在所有子任务执行完毕后,主任务才能执行
    836         
    837         //构造主任务障碍器  第一个参数子任务个数,第二参数主任务对象
    838         CyclicBarrier cb = new CyclicBarrier(7,new MainTask()); 
    839         
    840         new Thread(new SubTask("A",cb)).start();//创建子任务线程
    841         new Thread(new SubTask("B",cb)).start();
    842         new Thread(new SubTask("C",cb)).start();
    843         new Thread(new SubTask("D",cb)).start();
    844         new Thread(new SubTask("E",cb)).start();
    845         new Thread(new SubTask("F",cb)).start();
    846         new Thread(new SubTask("G",cb)).start();
    847         
    848     }    
    849     
    850     /**部分文档参考出处:http://blog.csdn.net/shimiso**/
    851 }
  • 相关阅读:
    JS事件学习笔记(思维导图)
    [logstash-input-file]插件使用详解
    echarts折线图,纵坐标数值显示不准确的问题解决
    IDEA 创建maven jar、war、 pom项目
    Lombok介绍、使用方法和总结
    Springboot2.0访问Redis集群
    springboot2.x 整合redis集群的几种方式
    SpringBoot 2.x 使用Redis作为项目数据缓存
    Springboot2.x使用redis作为缓存
    SpringBoot中application.yml基本配置详情
  • 原文地址:https://www.cnblogs.com/ciade/p/4770640.html
Copyright © 2011-2022 走看看