• java 线程 Thread 使用介绍,包含wait(),notifyAll() 等函数使用介绍


    (原创,转载请说明出处!谢谢--http://www.cnblogs.com/linguanh/)

     此文目的为了帮助大家较全面、通俗地了解线程 Thread 相关基础知识!

    目录:

           --线程的创建:

           --启动线程

           --线程的调度

           --Thread 类的简介

           --线程的同步/异步

           --wait() 和 notify(),notifyAll()方法

         

    在讲线程之前,先说下进程。

     

    进程:是运行系统中,每个独立运行的程序。例如win7,我既用酷狗软件听歌,又玩 LOL 游戏,又上QQ,那么这就有3个进程。

    线程:一个进程里面有很多线程,进程是由线程组成的,线程的结束不一定会导致进程结束,而一个进程的结束,则会连带它里面的所有线程被结束。

    ------------线程的创建:

    创建->

            java 中有两种方式:

            1,一种是通过实现Runnable 接口

            2,另一种是继承线程类 Thread

    实现Runnable接口的实例代码:

    1 class threadT implements Runnable{
    2     @Override
    3     public void run() {
    4         //在这编辑要执行的代码
    5     }
    6 }

    上述代码,通过实现 Runnable 的接口,重写接口函数 run() 来实现新建一个线程。类比,点击事件的接口 OnClickListener

    实现:

    1 Thread thread_test = new Thread(new threadT);
    2  //实例化代码一般放在主线程中,例如 main 中 或 onCreate()

    继承线程类Thread 的实例代码:

    1 class threadT1 extends Thread{
    2         public void run(){
    3          // edit your code
    4         }
    5  }

    实现:

    1 Thread thread_test = new ThreadT1();
    thread_test.start();

    上述两种方法的比较:

          本人建议使用第一种,即使用实现Runnable 接口的方法来新建线程。

          原因:

                1:避免java 的单一 继承带来的局限;

                2:和 onClickListener 点击事件一样,当你有多个线程时,使用Runnable 再在run内用一个 switch 就能分开使用;

    --------------启动线程:

    线程的启动一般都是通过方法执行 statrt() 进行的。

    完整 main 函数测试代码:

     1 package com.LGH.ew;
     2 
     3 /**
     4  *  Created by Administrator on 2015/4/25.
     5  *  各线程,当主线程main 执行完了,它们还会继续执行,彼此不影响
     6  *  多线程卖票 显示 demo,by LinGuanHong
     7  */
     8 public class threadTest {
     9     public static void main(String[] args){
    10         threadT t1 = new threadT1();//线程 1
    11         Thread t2 = new Thread(new ThreadT());//线程 2
    12        
    13         t2.start();
    14         t1.start();
    15     }
    16 }

    ------------线程的调度:

    调度是什么意思呢?就是 cpu 执行每个线程的顺序,注意,不一定是按顺序的,这个和线程的优先级有关!

    线程的调用是统一由JVM根据时间片来调度的,其执行顺序随机。大致执行流程如下:

    由上述可以看出, jvm 在执行多线程 程序的时候,在某一个时间段,其实也是只能运行一个线程,

    但是它用划分时间片段的机制来转换调用各个线程,这个时间片段很短!

    -----------Thread 类的简介

    java.lang.Thread 类:

        常用的方法有:

        ---public void start(); 启动该线程,其中调用了这个方法不一定就立即进行,还要看是否被调度到;

        ---public static Thread currentThread(); 静态方法,这个方法很重要,用来返回当前正在执行的线程对象引用;

        ---public final booleann isAlive();测试线程是否还活着;

        ---public Thread.State getState();返回该线程当前的状态,

                     分别有:

                              NEW 实例化了,但尚未启动的线程是这种状态,新建 态;

                              RUNNABLE 正在被执行的状态;

                              BLOCKED 受阻塞并等待某个监视器锁的线程态;

                              WAITING 无限期地等待另外一个线程来执行特地操作,等待 态;

                              TIMED_WAITING 等待另一个线程来执行取决于指定等待时间的操作,超时等待 态

                              TERMINATED 已退出的线程的状态,终止 态。

         ---public final String getName();返回线程名称,一般和setName(),连用;

         ---public final void setDaemon(boolean on);将该线程标记为守护线程;

         ---public static void sleep(long millis);在指定的毫秒内,让该线程暂停;

         ---public final void setPriority(int level);设置线程的优先级,可以是 1,5,10,分别是 低、普通、最高,默认是 5 ;

         ---public static void yield();线程让步,它会暂停该线程,把执行的机会让给相同或优先级更高的线程;

         ---public void final join();把某线程加入到某线程中去,被加者变为子线程;

         ---public void interrupt(); 中断线程.

    ------------线程的生命周期

    其生命周期可以总结为上面的 6个 状态,图解如下:

    -------------线程的同步/异步

    下面通过demo 代码说明,内涵 synchronized 保护机制

      1 package com.LGH.ew;
      2 
      3 /**
      4  *  Created by Administrator on 2015/4/25.
      5  *  各线程,当主线程main 执行完了,它们还会继续执行,彼此不影响
      6  *  多线程卖票 显示 demo,by LinGuanHong
      7  */
      8 public class threadTest { //卖火车票例子
      9     public static void main(String[] args){
     10         threadT T = new threadT();
     11         Thread t1 = new Thread(T);//线程 1
     12         t1.setName("1");// 设置 线程名字
     13         //t1.getState(); 这里有具体的线程对象,所以可以直接使用其类方法;
     14         t1.start();
     15         Thread t2 = new Thread(T);//线程 2
     16         t2.setName("2");
     17         t2.start();
     18         Thread t3 = new Thread(T);//线程 3
     19         t3.setName("3");
     20         t3.start();
     21         Thread t4 = new Thread(T);//线程 4
     22         t4.setName("4");
     23         t4.start();
     24         Thread t5 = new Thread(T);//线程 5
     25         t5.setName("5");
     26         t5.start();
     27     }
     28 }
     29 class threadT implements Runnable{ //实例化接口 
     30     private int tickets = 0;
     31     @Override
     32     public void run() {
     33         boolean control = true;
     34         while(control){
     35             control = sell();//调用sell 方法,大家可以通过改变这个函数的调用,来看异步、同步的效果
     36         }
     37     }
     38 
     39     public boolean sell(){//异步线程机制,会被打断,所谓打断,就是会出现 线程1 卖了第2张票时,线程3也卖了第2 张
     40         boolean control = true ;
     41         if(tickets<100){
     42             tickets ++;
     43             //在函数内,如果没有具体的线程对象,就要使用静态方法 currentThread() 返回当前正在执行的线程对象的引用,在使用类方法
     44             System.out.println(Thread.currentThread().getName()+":"+tickets);//同上
     45             Thread.State state = Thread.currentThread().getState();//同上
     46             System.out.println("State:"+state.toString());//输出当前的状态,正常是 runnable
     47         }else{
     48             control = false;
     49         }
     50         try{
     51             Thread.sleep(1);
     52         }catch (Exception e){
     53             e.printStackTrace();
     54         }
     55         return control;
     56     }
     57 
     58     //关键字 - synchronized 保护 当前 函数在执行时不被其他线程打断,同步线程机制
     59     //整体同步,效率低
     60     public synchronized boolean sell1(){ 
     61         boolean control = true ;
     62         if(tickets<100){
     63             tickets ++;
     64             //在函数内,如果没有具体的线程对象,就要使用静态方法 currentThread() 返回当前正在执行的线程对象的引用,在使用类方法
     65             System.out.println(Thread.currentThread().getName()+":"+tickets);//同上
     66             Thread.State state = Thread.currentThread().getState();//同上
     67            // System.out.println("State:"+state.toString());
     68         }else{
     69             control = false;
     70         }
     71         try{
     72             Thread.sleep(1);
     73         }catch (Exception e){
     74             e.printStackTrace();
     75         }
     76         return control;
     77     }
     78     //关键字 - synchronized 实质是一个对象锁
     79 
     80     public boolean sell2(){ // 条件 关键字 - synchronized 保护 当前 函数在执行时不被其他线程打断,同步线程机制
     81         boolean control = true ;
     82         synchronized(this) { //仅仅同步会操作到的共同部分变量,tickets,这样避免同步整体,提高效率
     83             if (tickets < 100) {
     84                 tickets++;
     85                 //在函数内,如果没有具体的线程对象,就要使用静态方法 currentThread() 返回当前正在执行的线程对象的引用,在使用类方法
     86                 System.out.println(Thread.currentThread().getName() + ":" + tickets);//同上
     87                 Thread.State state = Thread.currentThread().getState();//同上
     88                 // System.out.println("State:"+state.toString());
     89             } else {
     90                 control = false;
     91             }
     92         }
     93         try{
     94             Thread.sleep(1);
     95         }catch (Exception e){
     96             e.printStackTrace();
     97         }
     98         return control;
     99     }
    100 }

    -------------wait() 和 notify(),notifyAll()方法

    他们是同步机制中的重要部分,必须和 synchronized 关键字结合使用,即在 synchronized 代码块中使用!

    否在 抛出 Illegal..... 非法异常。

    wait() 被调用,当前线程将会被中断运行,并且放弃该对象的锁;

    执行了 notify() 后,会唤醒此对象等待池中的某个线程,使之成为可运行的线程;

    notifyAll()则唤醒所有;

     

    下面用一个具体的demo 说明:

    前言-------------

         生产者和消费者的问题,生产者将产品交给店员,而消费者从店员处取走产品,店员一次只能持有固定的产品,如果生产者生产过多了的产品,店员会叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;

         如果店中供不应求,店员会叫消费者等一会,等生产者生产了再叫消费者来拿。

    问题:

          生产者生产过快,消费者会漏掉一些,没取到;

          消费者比生产者快,消费者会拿到相同的;

     1 package com.LGH.ew.view;
     2 
     3 /**
     4  * Created by Administrator on 2015/4/25.
     5  */
     6 public class Product { //生产者、消费者问题
     7     public static void main(String[] args){
     8         clerk c = new clerk();
     9         Thread productT = new Thread(new Producer(c));//生产者线程
    10         Thread consumerT = new Thread(new Consumer(c));//消费者线程
    11         productT.start();
    12         consumerT.start();
    13     }
    14 }
    15 class clerk{ //店员
    16     private int product = 0; //默认 0 个产品
    17     public synchronized void addproduct(){ //生产出的产品,交给店员
    18         if(this.product>=20){
    19             try{
    20                 wait(); //产品过多,稍后再生产
    21             }catch (Exception e){
    22                 e.printStackTrace();
    23             }
    24         }else{
    25             product++;
    26             System.out.println("生产者生产第"+product+"个产品。");
    27             notifyAll(); //通知等待区的消费者可取产品
    28         }
    29     }
    30     public synchronized void getproduct(){ //消费者从店员处取产品
    31         if(this.product<=0){
    32             try{
    33                 wait(); //缺货,稍后再取
    34             }catch (Exception e){
    35                 e.printStackTrace();
    36             }
    37         }else{
    38             System.out.println("消费者取走了第:" + product + "产品。");
    39             product--;
    40             notifyAll(); //通知等待取得生产者可以继续生产
    41         }
    42     }
    43 }
    44 
    45 class Producer implements Runnable{ //生产者线程
    46 
    47     private clerk c;
    48     public Producer(clerk c){
    49         this.c = c;
    50     }
    51     @Override
    52     public void run() {
    53         System.out.println("生产者开始生产产品。");
    54         while(true){
    55             try{
    56                 Thread.sleep((int)(Math.random()*10)*100);
    57             }catch(Exception e){
    58                 e.printStackTrace();
    59             }
    60             c.addproduct(); //生产
    61         }
    62     }
    63 }
    64 
    65 class Consumer implements Runnable{ //消费者线程
    66 
    67     private clerk c ;
    68 
    69     public Consumer(clerk c){
    70         this.c = c;
    71     }
    72     @Override
    73     public void run() {
    74         System.out.println("消费者开始取走产品。");
    75         while(true){
    76             try{
    77                 Thread.sleep((int)(Math.random()*10)*100);
    78             }catch(Exception e){
    79                 e.printStackTrace();
    80             }
    81             c.getproduct(); //取产品
    82         }
    83     }
    84 }

    全文终,各位如果觉得还可以的话,请帮忙点个赞,让更多人能看到。谢谢

  • 相关阅读:
    java导入导出下载Excel,xls文件(带下拉框)
    java操作poi生成excel.xlsx(设置下拉框)下载本地和前端下载
    layui文件上传中如何先判断后再弹出文件选择框
    下载excle文件之工具
    eclipse 配置JDK
    layer实现关闭弹出层刷新父界面功能详解
    兼容ie9以下支持媒体查询和html5
    layui学习地址
    MATLAB拟合正态分布
    Matlab文件操作
  • 原文地址:https://www.cnblogs.com/linguanh/p/4698773.html
Copyright © 2020-2023  润新知