zoukankan      html  css  js  c++  java
  • java--多线程

    java---多线程

    一、线程简介
        线程:程序可执行的路径,或者说程序可执行的通道
        进程:一个个单独执行的程序或软件
        进程和线程的关系:线程是进程执行的路径、通道,多线程即有多个路径执行这个程序
        一个进程如果只有一个线程,那么这是个单线程程序,如果有多条线程,则为多线程程序
    二、生命周期


         
    创建多线程的方法:继承Thead父类和实现Runable接口

    1、继承Thead
    public class TheadDemo extends Thead{
           public void run()
           puclic static void main(String[] args){}
    }

    public class TheadDemo1 extends Thread {
    @Override
    public void run() {
    for(int i=0;i<10;i++){
    System.out.println(Thread.currentThread().getName()+" "+i);
    }
    }
    public static void main(String[] args){
    TheadDemo1 theadDemo1 = new TheadDemo1();
    TheadDemo1 theadDemo2 = new TheadDemo1();
    theadDemo1.start();
    theadDemo2.start();
    }


    2、实现Runable接口
    public class TheadDemo Implements Runable{
           puclic void run()
           puclic static void main(String[] args){}
    }

          public class RunableDemo implements Runnable {
                 @Override
                    public void run() {
                             for(int i=0;i<100;i++){
                             System.out.println(Thread.currentThread().getName()+""+i);                           //   Thread.currentThread()  获得当前执行线程的信息      getName()   得到线程的名字
                       }
              }
                   public static void main(String[] args){
                              RunableDemo runableDemo = new RunableDemo();
                             RunableDemo runableDemo1 = new RunableDemo();
                              Thread thread = new Thread(runableDemo,"线程一");                                           //new Thead(  要创建线程的类对象, 给线程起的名字);
                             Thread thread1 = new Thread(runableDemo1, "线程二");
                             thread.start();
                            thread1.start();
              }

        }
    run()方法:当一个线程启动后,就会自动去执行这个方法,当有多个线程的时候每个线程都会去调用run()方法,多个线程是没有执行顺序的,是由cpu随机分配,多个线程依次执行。main()方法主线程是不会去调用外部的run()方法的

    两种实现接口方法的区别:

       Thead:

               优点:使用方便          缺点:单继承的局限性

        Runable:

                优点:可以多继承       缺点:使用麻烦

    三、常用的方法:

         setPriority(int  new Priority):更改线程的优先级,默认值是5,范围是1-10。1的优先级最低,10的优先级最高

         join():插入:在当前的线程执行中,如果使用join()插入一个线程,那么就会先执行插入的线程,并且要执行完毕才会再执行原来的线程

         sleep(long millis):设置线程休眠,时间以毫秒为单位。设置线程在指定的时间内休眠,不运行。

         yield()暂停正在运行的线程,礼让执行:该方法就像公交车上的让座,被让座的可能接收也可能不接受,所以线程既可能执行原来的也可能执行插入进来的线程

    案例:

          slepp和setPriority:

      join():

         public class JoinDemo implements Runnable {
               @Override
                public void run() {
                       for(int i=0;i<10;i++){
                        System.out.println(Thread.currentThread().getName()+" "+i);
                       }
                }
                 public static void main(String[] args) throws InterruptedException {
                      JoinDemo joinDemo = new JoinDemo();
                      Thread thread = new Thread(joinDemo);
                      thread.start();
                       for(int i=0;i<10;i++){
                      System.out.println(Thread.currentThread().getName());
                       if(i==3){
                          //join() 插队执行
                      thread.join();
                            //yield() 礼让执行,可能礼让成功,也可能失败
                            //Thread.yield();
                          }
                          }
                 }
           }

     四、同步锁

           当多个线程操作同一共享资源时,将引发数据不安全问题,如下:利用线程休眠来模拟网络延迟,多个线程去一家商店买裤子

        public class BuyGoodsDemo implements Runnable {
               private int num=10; //裤子总数
               private int count=0;//购买到的是第几条裤子
              @Override
               public void run() {
                        //每一个人买过之后,num减一,count加一
                     while(true){
                           if(num<=0){
                                //裤子卖完,跳出循环
                                 break;
                                }
                             num--;
                             count++;
                               try{
                                       //模拟网络延迟
                                        Thread.sleep(100);
                                    }catch (InterruptedException e){
                                        e.printStackTrace();
                                     }
                                 System.out.println(Thread.currentThread().getName()+"买到的是第"+count+"条裤子,还有"+num+"条");
                        }
                }
                public static void main(String[] args){
                        BuyGoodsDemo buyGoodsDemo = new BuyGoodsDemo();
                        Thread t1 = new Thread(buyGoodsDemo, "小敏");
                        Thread t2 = new Thread(buyGoodsDemo, "小青");
                         Thread t3 = new Thread(buyGoodsDemo, "小红");
                         Thread t4 = new Thread(buyGoodsDemo, "小白");
                         t1.start();
                            t2.start();
                         t3.start();
                          t4.start();
                         }
           }

    执行后的结果:

    原因:这时因为当一个线程执行run()方法后,num和count被操作,但是再往后执行就出现了网络延迟,第一个执行的线程还有执行完毕,后边的线程已经将num和count执行了,当网络恢复了,

              第一个线程再向下执行,此时的每个参数数值已经是最后一个线程执行后的参数数值

     解决方法:synchronized:同步锁,将容易出现问题的代码进行包裹,包裹后就成了单线程。

     两种写法:同步代码块和同步方法

    第一种:同步代码块:

    public class BuyGoodsDemo1 implements Runnable {
    /**
    * synchronized:同步锁,将容易出现问题的代码进行包裹,包裹后就成为了单线程
    * 一、同步代码块(该例中用同步代码块)
    * 二、同步方法
    * */
    private int num=10;
    private int count=0;//购买到的是第几条裤子
    @Override
    public void run() {
    //每一个人买过之后,num减一,count加一
    while(true){

              //...........................................................................................................................
                      synchronized (this){
                            if(num<=0){
                         //裤子卖完,跳出循环
                               break;
                          }
                          num--;
                           count++;
                           System.out.println(Thread.currentThread().getName()+"买到的是第"+count+"条裤子,还有"+num+"条");
                          }

              //...............................................................................................................................
    try{
    //模拟网络延迟
    Thread.sleep(100);
    }catch (InterruptedException e){
    e.printStackTrace();
    }

    }

    }
    public static void main(String[] args){
    BuyGoodsDemo1 buyGoodsDemo = new BuyGoodsDemo1();
    Thread t1 = new Thread(buyGoodsDemo, "小敏");
    Thread t2 = new Thread(buyGoodsDemo, "小青");
    Thread t3 = new Thread(buyGoodsDemo, "小红");
    Thread t4 = new Thread(buyGoodsDemo, "小白");
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    }
    }

          第二种:同步方法

    public class BuyGoodsDemo2 implements Runnable {
    /**
    * synchronized:同步锁,将容易出现问题的代码进行包裹,包裹后就成为了单线程
    * 一、同步代码块
    * 二、同步方法(该例中用同步方法)
    * */
    private int num=10;
    private int count=0;//购买到的是第几条裤子
    @Override
    public void run() {
    //每一个人买过之后,num减一,count加一
    while(true){

    if(!buy()){
    break;
    }

    try{
    //模拟网络延迟
    Thread.sleep(100);
    }catch (InterruptedException e){
    e.printStackTrace();
    }

    }

    }
    public synchronized boolean buy(){
    if(num<=0){
    //裤子卖完,跳出循环
    return false;
    }
    num--;
    count++;
    System.out.println(Thread.currentThread().getName()+"买到的是第"+count+"条裤子,还有"+num+"条");
    return true;
    }
    public static void main(String[] args){
    BuyGoodsDemo2 buyGoodsDemo = new BuyGoodsDemo2();
    Thread t1 = new Thread(buyGoodsDemo, "小敏");
    Thread t2 = new Thread(buyGoodsDemo, "小青");
    Thread t3 = new Thread(buyGoodsDemo, "小红");
    Thread t4 = new Thread(buyGoodsDemo, "小白");
    t1.start();
    t2.start();
    t3.start();
    t4.start();
    }
    }








    练习:

    一、 使用多线程模拟年轻人与老人年徒步爬到1500米的山顶

    
    

    需求讲解:

    
    

    年轻人每爬100米需要300毫秒,

    
    

    老人年爬完100米需要1000毫秒,

    
    

    利用线程的休眠分别模拟老年人与年轻人每爬100米需要的时间,实现该案例。

    二、 利用多线程模拟叫号看病

    需求讲解:

    1、某科室一天需看普通号50个,特需号10

    2、特需号看病时间是普通号的2倍(设置线程的休眠)

    3、开始时普通号和特需号并行叫号(两个线程同时分别被调度),叫到特需号的概率比普通号高(设置线程的优先级)

    4、当普通号叫完第10号时,要求先看完全部特需号,再看普通号(join方法)

    使用多线程模拟这一过程,执行效果大致如下:

    代码:第一题:
    public class HomeWorkThead implements Runnable {
    @Override
    public void run() {
    for(int i=0;i<10;i++){
    try {
    Thread.sleep(3000);//设置vip号的诊断时间
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName()+i);
    }

    }
    public static void main(String[] args){
    HomeWorkThead homeWorkThead = new HomeWorkThead();
    Thread thread = new Thread(homeWorkThead,"vip号");
    //设置主线程为普通号
    Thread.currentThread().setName("普通号");
    thread.setPriority(10);//设置vip号的优先级
    thread.start();
    for(int i=0;i<50;i++){
    System.out.println(Thread.currentThread().getName()+i);
    if(i==10){
    try {
    thread.join();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    }
    }
    }


    第二题代码:
    public class HomeWorkThead2 implements Runnable {
    @Override
    public void run() {
    if(Thread.currentThread().getName().equals("年轻人")) {
    for (int i = 0; i < 15; i++) {
    try {
    Thread.sleep(300);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "跑完一百米");
    if(i==14){
    System.out.println(Thread.currentThread().getName()+"跑完了");
    }
    }
    }
    if(Thread.currentThread().getName().equals("老年人")){for (int i = 0; i < 15; i++) {
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + "跑完一百米");
    if(i==14){
    System.out.println(Thread.currentThread().getName()+"跑完了");
    }
    }}
    }
    public static void main(String[] args){
    HomeWorkThead2 h1 = new HomeWorkThead2();
    HomeWorkThead2 h2 = new HomeWorkThead2();

    Thread t1 = new Thread(h1, "年轻人");
    Thread t2 = new Thread(h2, "老年人");

    t1.start();
    t2.start();
    }
    }
     


  • 相关阅读:
    elasticsearch(0.90.10)安装配置+超多插件!!
    【架构】基于Nutch+Hadoop+Hbase+ElasticSearch的网络爬虫及搜索引擎
    Elasticsearch(1.1.1)基础教程pdf
    hadoop1.2.1+hbase0.94.11+nutch2.2.1+elasticsearch0.90.5安装配置攻略
    安装和使用 Elasticsearch(1.1.1)+marvel插件、Kibana插件
    nutch2.1+mysql+elasticsearch整合linux单机部署
    Nutch 快速入门(Nutch 2.2.1+Hbase+Solr)
    Linux中VMware虚拟机增加磁盘空间的扩容操作
    java8使用stream的collect进行list转map注意事项
    Java 8 指南
  • 原文地址:https://www.cnblogs.com/fbbg/p/11123122.html
Copyright © 2011-2022 走看看