• 黑马程序员——Java基础---多线程


    ------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! ------- 

    一、多线程概述

            要理解多线程,就必须理解线程。而要理解线程,就必须知道进程。

    1、 进程

            是一个正在执行的程序。例如,qq等

            每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。//例如登录qq,你需要输入账号、密码、点击登录等

    2、线程

             就是进程中的一个独立的控制单元。线程在控制着进程的执行。只要进程中有一个线程在执行,进程就不会结束。//登录qq时,会验证密码账号等线程

            一个进程中至少有一个线程。即  进程:线程=1:n(n为大于等于1的整数)

    3、多线程

            在java虚拟机启动的时候会有一个java.exe的执行程序,也就是一个进程。该进程中至少有一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。JVM启动除了执行一个主线程,还有负责垃圾回收机制的线程。像这种在一个进程中有多个线程执行的方式,就叫做多线程。

    4、多线程存在的意义

            多线程的出现能让程序产生同时运行效果。可以提高程序执行效率。

             例如:在java.exe进程执行主线程时,如果程序代码特别多,在堆内存中产生了很多对象,而同时对象调用完后,就成了垃圾。如果垃圾过多就有可能是堆内存出现内存不足的现象,只是如果只有一个线程工作的话,程序的执行将会很低效。而如果有另一个线程帮助处理的话,如垃圾回收机制线程来帮助回收垃圾的话,程序的运行将变得更有效率。现实生活中,你可以一边烧水,一边切菜,为了做汤。

    5、计算机CPU的运行原理

             我们电脑上有很多的程序在同时进行,就好像cpu在同时处理这所以程序一样。但是,在一个时刻,单核的cpu只能运行一个程序。而我们看到的同时运行效果,只是cpu在多个进程间做着快速切换动作。就好像灯泡一样,它是在不停的闪灭,而我们眼睛接受不全,便以为是一直亮。

             而cpu执行哪个程序,是毫无规律性的。这也是多线程的一个特性:随机性。哪个线程被cpu执行,或者说抢到了cpu的执行权,哪个线程就执行。而cpu不会只执行一个,当执行一个一会后,又会去执行另一个,或者说另一个抢走了cpu的执行权。至于究竟是怎么样执行的,只能由cpu决定。就好像皇帝跟妃子的关系。

     

    二、创建线程的方式

            创建线程共有两种方式:继承方式和实现方式(简单的说)。

    1、 继承方式

            通过查找java的帮助文档API,我们发现java中已经提供了对线程这类事物的描述的类——Thread类。这第一种方式就是通过继承Thread类,然后复写其run方法的方式来创建线程。

    创建步骤:

            a,定义类继承Thread。

            b,复写Thread中的run方法。

                 目的:将自定义代码存储在run方法中,让线程运行。

            c,创建定义类的实例对象。相当于创建一个线程。

            d,用该对象调用线程的start方法。该方法的作用是:启动线程,调用run方法。

    注:如果对象直接调用run方法,等同于只有一个线程在执行,自定义的线程并没有启动。

    覆盖run方法的原因:

            Thread类用于描述线程。该类就定义了一个功能,用于存储线程要执行的代码。该存储功能就run方法。也就是说,Thread类中的run方法,用于存储线程要运行的代码。

    程序示例:

     1 /*
     2 
     3 创建两个线程 贡献一个 资源,
     4 加入主线程  便有三个线程
     5 */
     6 class Demo extends Thread//继承Thread类
     7 {
     8      public int x=60;//定义计数器
     9     public Demo(String name)
    10     {
    11         super(name);
    12     }
    13     public void run()//复写run方法
    14     {
    15 
    16         while(x>0)
    17         {
    18             System.out.println(Thread.currentThread().getName()+".....sale:"+"...."+x);//获取线程名称以及对应的次数
    19                     x--;
    20         }
    21     }
    22 }
    23 class ThreadDemo
    24 {
    25     public static void main(String[] args)
    26     {
    27         Demo d=new Demo("--one--");//创建线程名称
    28         Thread d1=new Thread(d);//共用一个资源的两个线程
    29         Thread d2=new Thread(d);
    30         
    31         d1.start();//start()方法可以调用run()方法 实现多线程
    32         d2.start();
    33 
    34         
    35             for(int x=0;x<60;x++)//主线程  打印  main
    36             {
    37                 System.out.println("---main---"+x);
    38             }
    39         
    40     }
    41 }

    程序运行结果每一次都可能出现不同种的情况,而下图出现的次序错乱问题,应该是计算机为多核,打印到显示台上才会如此。如图:

    第二种方式:实现Runnable接口:

     1 /*
     2 需求:简单的卖票程序。
     3 多个窗口同时买票。
     4 
     5 
     6 创建线程的第二种方式:实现Runable接口
     7 
     8 步骤:
     9 1,定义类实现Runnable接口
    10 2,覆盖Runnable接口中的run方法。
    11     将线程要运行的代码存放在该run方法中。
    12 
    13 3,通过Thread类建立线程对象。
    14 4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
    15     为什么要将Runnable接口的子类对象传递给Thread的构造函数。
    16     因为,自定义的run方法所属的对象是Runnable接口的子类对象。
    17     所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
    18 
    19 
    20 5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。
    21 
    22 
    23 
    24 实现方式和继承方式有什么区别呢?
    25 
    26 实现方式好处:避免了单继承的局限性。
    27 在定义线程时,建立使用实现方式。
    28 
    29 两种方式区别:
    30 继承Thread:线程代码存放Thread子类run方法中。
    31 实现Runnable,线程代码存在接口的子类的run方法。
    32 
    33 
    34 
    35 
    36 */
    37 
    38 class Ticket implements Runnable//extends Thread
    39 {
    40     private  int tick = 100;//有一百张票
    41     public void run()
    42     {
    43         while(true)
    44         {
    45             if(tick>0)
    46             {
    47                 System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);//打印线程名称跟票数
    48             }
    49             else
    50                 break;
    51         }
    52     }
    53 }
    54 
    55 
    56 class  TicketDemo
    57 {
    58     public static void main(String[] args) 
    59     {
    60 
    61         Ticket t = new Ticket();
    62 
    63         Thread t1 = new Thread(t);//创建了一个线程;
    64         Thread t2 = new Thread(t);//创建了一个线程;
    65         Thread t3 = new Thread(t);//创建了一个线程;
    66         Thread t4 = new Thread(t);//创建了一个线程;
    67         t1.start();//运行该线程,调用run()方法
    68         t2.start();
    69         t3.start();
    70         t4.start();
    71 
    72 
    73         /*
    74         Ticket t1 = new Ticket();
    75         //Ticket t2 = new Ticket();
    76         //Ticket t3 = new Ticket();
    77         //Ticket t4 = new Ticket();
    78 
    79         t1.start();
    80         t1.start();
    81         t1.start();
    82         t1.start();
    83         */
    84 
    85     }
    86 }

    三、两种方式的区别和线程的几种状态

    1、两种创建方式的区别

            继承Thread:线程代码存放在Thread子类run方法中。

            实现Runnable:线程代码存放在接口子类run方法中。      

    2、几种状态

            被创建:等待启动,调用start启动。

             运行状态:具有执行资格和执行权。

             临时状态(阻塞):有执行资格,但是没有执行权。

             冻结状态:遇到sleep(time)方法和wait()方法时,失去执行资格和执行权,sleep方法时间到或者调用notify()方法时,获得执行资格,变为临时状态。

             消忙状态:stop()方法,或者run方法结束。

    注:当已经从创建状态到了运行状态,再次调用start()方法时,就失去意义了,java运行时会提示线程状态异常。

    四、线程安全问题

     1 /*
     2 通过分析,发现,打印出0,-1,-2等错票
     3 
     4 多线程的运行出现了问题
     5 问题的原因:
     6         当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
     7         另一个线程参与进来执行。导致共享数据的错误
     8 
     9 解决办法:
    10         对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
    11 
    12 
    13 java对于多线程的安全问题提供了专业的解决方式。
    14 就是同步代码块
    15 synchronized(对象)
    16 {
    17     需要被同步的代码
    18 }
    19 对象如同锁。持有锁的线程可以在同步中执行。
    20 没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有 获取锁
    21 
    22 火车上的卫生间----经典
    23 
    24 同步的前提:
    25 1    必须要有两个或者两个以上的线程
    26 2    必须是多个线程使用同一个锁
    27 
    28 
    29 必须保证同步中只能有一个线程在运行
    30 
    31 好处:    解决了多线程的安全问题
    32 
    33 弊端:    多个线程需要判断锁,较为消耗资源 
    34 
    35 
    36 */
    37 
    38 class Ticket implements Runnable
    39 {
    40     private int tick=100;
    41     Object obj =new Object();
    42     public void run()
    43     {
    44         while(true)
    45         {
    46             synchronized(obj)//加锁,锁可以是任意存在的对象
    47             {
    48                 if(tick>0)
    49                 {
    50                     //try{Thread.sleep(10);}catch(Exception e){}//线程暂时休眠
    51                     System.out.println(Thread.currentThread().getName()+"....sale:"+tick--);//打印线程名称和票编号
    52                 }
    53                 else 
    54                     break;
    55             }
    56         }
    57     }
    58 }
    59 class TicketDemo2
    60 {
    61     public static void main(String[] args)
    62     {
    63         
    64         Ticket t = new Ticket();
    65 
    66         Thread t1 = new Thread(t);
    67         Thread t2 = new Thread(t);
    68         Thread t3 = new Thread(t);
    69         Thread t4 = new Thread(t);
    70         t1.start();
    71         t2.start();
    72         t3.start();
    73         t4.start();
    74     }
    75 }

    五、静态函数的同步方式

    如果同步函数被静态修饰后,使用的锁是什么呢?

            通过验证,发现不在是this。因为静态方法中也不可以定义this。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。如:

            类名.class 该对象的类型是Class

    这就是静态函数所使用的锁。而静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class

    经典示例:

     1 /*
     2 单例设计模式。
     3 
     4 
     5 */
     6 //饿汉式
     7 class Single
     8 {
     9     private static final Single s=new Single();//创建Single类并分配资源
    10     private  Single(){}
    11     public static Single getInstance()
    12     {
    13         return s;
    14     }
    15 }
    16 
    17 
    18 //懒汉式
    19 class Single
    20 {
    21     private static Single s=null;//创建Single类,使其为空
    22     private Single(){}
    23     public static Single getInstance()
    24     {
    25         if (s==null)
    26         {
    27             synchronized(Single.class)//Single.class文件在类创建时,便存在
    28             {
    29                 if(s==null)
    30                     s=new Single();//分配资源
    31             }
    32         }
    33         return s;
    34     }
    35 }

    六、死锁

            当同步中嵌套同步时,就有可能出现死锁现象。

     1 /*
     2 死锁
     3 同步中嵌套同步。A锁套B锁,B锁套A锁。
     4 */
     5 class Test implements Runnable
     6 {
     7     private boolean flag;
     8     Test(boolean flag)
     9     {
    10         this.flag = flag;
    11     }
    12 
    13     public void run()
    14     {
    15         if(flag)
    16         {
    17             while(true)
    18             {
    19                 synchronized(MyLock.locka)//A锁
    20                 {
    21                     System.out.println(Thread.currentThread().getName()+"...if locka ");
    22                     synchronized(MyLock.lockb)//B锁
    23                     {
    24                         System.out.println(Thread.currentThread().getName()+"..if lockb");                    
    25                     }
    26                 }
    27             }
    28         }
    29         else
    30         {
    31             while(true)
    32             {
    33                 synchronized(MyLock.lockb)//B锁
    34                 {
    35                     System.out.println(Thread.currentThread().getName()+"..else lockb");
    36                     synchronized(MyLock.locka)//A锁
    37                     {
    38                         System.out.println(Thread.currentThread().getName()+".....else locka");
    39                     }
    40                 }
    41             }
    42         }
    43     }
    44 }
    45 
    46 
    47 class MyLock//创建两个锁
    48 {
    49     static Object locka = new Object();
    50     static Object lockb = new Object();
    51 }
    52 
    53 class  DeadLockTest
    54 {
    55     public static void main(String[] args) 
    56     {
    57         Thread t1 = new Thread(new Test(true));//创建两个线程
    58         Thread t2 = new Thread(new Test(false));
    59         t1.start();//运行线程,调用run()方法
    60         t2.start();
    61     }
    62 }

    死锁运行程序 结果如下图:

    七、线程间通信

            其实就是多个线程在操作同一个资源,但是操作的动作不同。如一个 存入,一个输出。

    1、使用同步操作同一资源的示例:

      1 /*
      2 线程间通讯:
      3 其实就是多个线程在操作同一个资源,
      4 但是操作的动作不同。
      5 
      6 */
      7 class Res//定义资源 包括姓名 性别  以及否的初设定
      8 {
      9     String name;
     10     String sex;
     11     boolean flag = false;
     12 }
     13 
     14 class Input implements Runnable//存入  继承Runnable
     15 {
     16     private Res r ;
     17     Input(Res r)
     18     {
     19         this.r = r;
     20     }
     21     public void run()//复写run方法
     22     {
     23         int x = 0;//定义变量,改变存入资源的种类
     24         while(true)
     25         {
     26             synchronized(r)//
     27             {
     28 
     29                 if(r.flag)//当有资源。flag为真时,先等待,避免多存
     30                     try{r.wait();}catch(Exception e){}
     31                 if(x==0)
     32                 {
     33                     r.name="mike";
     34                     r.sex="man";
     35                 }
     36                 else
     37                 {
     38                     r.name="丽丽";
     39                     r.sex = "女女女女女";
     40                 }
     41                 x = (x+1)%2;//改变x的奇偶
     42                 r.flag = true;//改变flag的值,说明已存
     43                 r.notify();//唤醒其他线程
     44             }
     45         }
     46     }
     47 }
     48 
     49 class Output implements Runnable//输出    继承Runnable
     50 {
     51     private Res r ;
     52     
     53     Output(Res r)
     54     {
     55         this.r = r;
     56     }
     57     public void run()//复写run方法
     58     {
     59         while(true)
     60         {
     61             synchronized(r)//
     62             {
     63                 if(!r.flag)//当flag为假时,即没有资源时,先等待
     64                     try{r.wait();}catch(Exception e){}
     65                 System.out.println(r.name+"...."+r.sex);//打印资源
     66                 r.flag = false;//改变flag的值,说明已取出
     67                 r.notify();//唤醒其他线程
     68             }
     69         }
     70     }
     71 }
     72 
     73 
     74 class  InputOutputDemo
     75 {
     76     public static void main(String[] args) 
     77     {
     78         Res r = new Res();
     79 
     80         Input in = new Input(r);
     81         Output out = new Output(r);
     82 
     83         Thread t1 = new Thread(in);
     84         Thread t2 = new Thread(out);
     85 
     86         t1.start();
     87         t2.start();
     88     }
     89 }
     90 
     91 
     92 //notifyAll();
     93 
     94 /*
     95 wait:
     96 notify();
     97 notifyAll();
     98 
     99 都使用在同步中,因为要对持有监视器(锁)的线程操作。
    100 所以要使用在同步中,因为只有同步才具有锁。
    101 
    102 为什么这些操作线程的方法要定义Object类中呢?
    103 因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,
    104 只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。
    105 不可以对不同锁中的线程进行唤醒。
    106 
    107 也就是说,等待和唤醒必须是同一个锁。
    108 
    109 而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。
    110 
    111 
    112 */

    程序运行部分截图如下:

     几个小问题:

            1)wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?

                    a,这些方法存在与同步中。

                    b,使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。

                    c,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

            2)wait(),sleep()有什么区别?

                  wait():释放cpu执行权,释放锁。

                  sleep():释放cpu执行权,不释放锁。

            3)为甚么要定义notifyAll?

            因为在需要唤醒对方线程时。如果只用notify,容易出现只唤醒本方线程的情况。导致程序中的所以线程都等待。

    2、JDK1.5中提供了多线程升级解决方案。

            将同步synchronized替换成显示的Lock操作。将Object中wait,notify,notifyAll,替换成了Condition对象。该Condition对象可以通过Lock锁进行获取,并支持多个相关的Condition对象。

    升级解决方案的示例:

      1 import java.util.concurrent.locks.*;
      2 
      3 class ProducerConsumerDemo2 
      4 {
      5     public static void main(String[] args) 
      6     {
      7         Resource r = new Resource();//建立资源
      8 
      9         Producer pro = new Producer(r);//创建生产者与消费者,操作的是同一个资源
     10         Consumer con = new Consumer(r);
     11 
     12         Thread t1 = new Thread(pro);//生产者两个线程
     13         Thread t2 = new Thread(pro);
     14         Thread t3 = new Thread(con);//消费者两个线程
     15         Thread t4 = new Thread(con);
     16 
     17         t1.start();//运行线程,调用run()方法
     18         t2.start();
     19         t3.start();
     20         t4.start();
     21 
     22     }
     23 }
     24 
     25 /*
     26 JDK1.5 中提供了多线程升级解决方案。
     27 将同步Synchronized替换成现实Lock操作。
     28 将Object中的wait,notify notifyAll,替换了Condition对象。
     29 该对象可以Lock锁 进行获取。
     30 该示例中,实现了本方只唤醒对方操作。
     31 Lock:替代了Synchronized
     32     lock 
     33     unlock
     34     newCondition()
     35 
     36 Condition:替代了Object wait notify notifyAll
     37     await();
     38     signal();
     39     signalAll();
     40 */
     41 class Resource
     42 {
     43     private String name;//创建资源固有属性
     44     private int count = 1;
     45     private boolean flag = false;
     46             //  t1    t2
     47     private Lock lock = new ReentrantLock();//创建锁
     48 
     49     private Condition condition_pro = lock.newCondition();//将锁的情况 分为两份,线程使用的是自己派别的锁
     50     private Condition condition_con = lock.newCondition();
     51 
     52 
     53 
     54     public  void set(String name)throws InterruptedException
     55     {
     56         lock.lock();
     57         try
     58         {
     59             while(flag)//flag  为真时,代表有资源
     60                 condition_pro.await();//t1,t2  生产者等待
     61             this.name = name+"--"+count++;
     62 
     63             System.out.println(Thread.currentThread().getName()+"...生产者.."+this.name);//打印线程信息到控制台上
     64             flag = true;
     65             condition_con.signal();//唤醒消费者
     66         }
     67         finally
     68         {
     69             lock.unlock();//释放锁的动作一定要执行。
     70         }
     71     }
     72 
     73 
     74     //  t3   t4  
     75     public  void out()throws InterruptedException
     76     {
     77         lock.lock();
     78         try
     79         {
     80             while(!flag)//flag 为假时, 代表没有资源
     81                 condition_con.await();//消费者等待
     82             System.out.println(Thread.currentThread().getName()+"...消费者........."+this.name);//打印线程信息到控制台上
     83             flag = false;
     84             condition_pro.signal();//唤醒生产者
     85         }
     86         finally
     87         {
     88             lock.unlock();//释放锁
     89         }
     90         
     91     }
     92 }
     93 
     94 class Producer implements Runnable//生产者的类,继承Runnable
     95 {
     96     private Resource res;
     97 
     98     Producer(Resource res)
     99     {
    100         this.res = res;
    101     }
    102     public void run()  //复写run()方法
    103     {
    104         while(true)
    105         {
    106             try
    107             {
    108                 res.set("+商品+");  //在资源中增加商品
    109             }
    110             catch (InterruptedException e)
    111             {
    112             }
    113             
    114         }
    115     }
    116 }
    117 
    118 class Consumer implements Runnable//消费者的类,继承Runnable
    119 {
    120     private Resource res;
    121 
    122     Consumer(Resource res)
    123     {
    124         this.res = res;
    125     }
    126     public void run()//复写 run()方法
    127     {
    128         while(true)
    129         {
    130             try
    131             {
    132                 res.out();//移除资源
    133             }
    134             catch (InterruptedException e)
    135             {
    136             }
    137         }
    138     }
    139 }

    改程序运行结果部分截图如下:

    八、停止线程

     1 /*
     2 stop方法已经过时
     3 
     4 如何停止线程?
     5 只有一种,run方法结束
     6 开启多线程运行,运行代码通常是循环结构
     7 
     8 只要控制住循环,就可以让run方法结束,也就是线程结束
     9 就是将while等判断语句中加入限制条件让其运行一段时间后停止运行
    10 
    11 特殊情况:
    12 当线程处于冻结状态就不会读取到标记。那么线程就不会结束
    13 例如线程就如等待状态,没有其他唤醒线程,将会导致线程运行不到后面的结束 语句
    14 
    15 当没有指定的方式让冻结的线程恢复到运行状态时,就需要对冻结了的线程进行清除
    16 强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束。
    17 
    18 强制的方法为中断  interrupt();   
    19 例如
    20 当主函数运行将要结束时,使进入冻结状态的t1进程,强制将其终止
    21 t1.interrupt();
    22 
    23 
    24 */
    25 
    26 
    27 /*
    28 该函数有三个线程,主线程和t1和t2两个线程。  两个线程中while可能会进入死循环,需要强制结束,
    29 第一种方法:    通过调用,是while中的条件不满足,这时程序会结束
    30 第二种方法:    使用中断函数interrupt();
    31 */
    32 class StopThread implements Runnable
    33 {
    34     private boolean flag =true;
    35     public  void run()
    36     {
    37         while(flag)
    38         {
    39             
    40             System.out.println(Thread.currentThread().getName()+"....run");
    41         }
    42     }
    43     public void changeFlag()
    44     {
    45         flag = false;
    46     }
    47 }
    48 
    49 
    50 
    51 
    52 class  StopThreadDemo
    53 {
    54     public static void main(String[] args) 
    55     {
    56         StopThread st = new StopThread();//新建停止线程
    57         
    58         Thread t1 = new Thread(st);
    59         Thread t2 = new Thread(st);
    60 
    61 
    62         //t1.setDaemon(true);//设置为守护线程,
    63         //t2.setDaemon(true);
    64         t1.start();
    65         t2.start();
    66 
    67         int num = 0;
    68 
    69         while(true)
    70         {
    71             if(num++ == 60)
    72             {
    73                 st.changeFlag();//当满足条件时改变Flag状态,使线程结束
    74                 //t1.interrupt();////清除冻结状态 ,唤醒线程
    75                 //t2.interrupt();
    76                 break;
    77             }
    78             System.out.println(Thread.currentThread().getName()+"......."+num);
    79         }
    80         System.out.println("over");
    81     }
    82 }

    程序运行结果部分截图如下:

    扩展小知识:

     1 /*
     2 目的:  学习join的运用
     3 join:
     4     当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行
     5     join可以 用来临时加入线程执行。
     6 
     7 即在主函数中,出现t1.join()时,只能等t1线程执行完成后,才能执行主函数中的线程
     8 如果在t1线程中加入了  t2.join()时,只能等t2线程执行完成后,才能执行主函数中的线程
     9 
    10 注意:   t1.join()如果在主函数中出现,只与t1和主线程有关
    11 
    12 当t1有可能进入冻结状态时,可以使其中断,之后便可以执行主函数。
    13     假使又使t1唤醒进入执行状态,将出现  异常
    14 
    15 
    16 
    17 
    18 同步的线程中   cpu决定哪个线程将会执行,然而执行将会有一个频率,就是线程具有优先级
    19 
    20 从1到10;默认线程的优先级为5;10为最高,1为最低;
    21 因为是常量  为了阅读性 MAX_PRIORITY     max_priority
    22                         MIN_PRIORITY    min_priority
    23                         MORM_PRIORITY    morm_priority
    24         改变线程的优先级        t1.setPriority(Thread.MAX_PRIORITY);
    25 
    26 MAX_PRIORITY 
    27 MIN_PRIORITY
    28 MORM
    29 
    30 Thread.yield();   线程休息一下,将cpu的使用权,推给其他线程
    31 Thread.yield();    Thread.yield  thread.yield    
    32 */
    33 class Demo implements Runnable
    34 {
    35     public void run()
    36     {
    37         for(int x=0;x<70;x++)
    38         {
    39             System.out.println(Thread.currentThread+"........"+x);
    40             Thread.yield();
    41             
    42         }
    43     }
    44 }
    45 class JoinDemo
    46 {
    47     public static void main(String[]  args) throws Exception
    48     {
    49         Demo d=new Demo();
    50         Thread t1=new Thread(d);
    51         Thread t2=new Thread(d);
    52         t1.start();
    53         //t1.setPriority(Thread.MAX_PRIORITY);
    54         t2.start();
    55         //t1.join();
    56         for(int x=0;x<80;x++)
    57         {
    58             //System.out.println("main...."+x);
    59         }
    60         System.out.println("over");
    61     }
    62 
    63 }

    自我总结:

         线程的由来是继承Thread或者实现Runnable,单线程可以认为是要做完某事才能做另外一件事,因此很负责很安全,同样的会导致效率比较慢,而多线程,可以看做同时做很多事,因此效率会比较高,但同时可能会带来安全隐患,因此需要用到锁这样的工具。

    如果是很多人来做一件事情时,就需要有标记即flag,需要告诉别人,自己完成到哪儿了。

    而有时某些人会陷入困境中,做很多无用功,这时需要别人来制止它的行为。即,强制结束。

    而某些人会陷入迷茫,无事可做。要么唤醒它,要么结束它。

    甚至会有那么一些人陷入内乱,导致无法工作,即死锁。这是我们要避免的情况。

    而有些人是为了某些人的存在而存在的。即守护线程。如果某些人不存在了,那么有些人也就没有戏了。

    而有些毒瘤的人加入某组织,毒瘤不死,组织无法运行。即  join()

  • 相关阅读:
    Notepad++ 配置信息导出导入(快捷键配置导出导入等等)
    SQL 删除重复数据
    PostgreSQL Update 根据B表更新A表
    桌面应用基本创建流程
    Android shape和selector完全总结
    Android 第三方框架之Charts
    java常见五种排序方式
    Objective-c之字典精讲
    OC语言之---NSArray
    Objective-c编程之NSString精讲
  • 原文地址:https://www.cnblogs.com/ktlshy/p/4715197.html
走看看 - 开发者的网上家园