16_多线程

  • Post author:
  • Post category:其他




百知教育 – 孙帅 – 16_多线程



01_线程的概念和实现线程的方式



  • 什么是

    进程

    • 程序是静止的,只有真正运行时的程序,才被称为

      进程



    • 单核CPU


      在任何时间点上,只能运行一个进程;


      宏观并行、微观串行




  • 什么是线程

    • 线程

      ,又称为

      轻量级进程(Light Weight Process)。

      是程序中的


      一个顺序控制流程


      ,同时也是


      CPU的基本调度单位





      进程由多个线程组成


      ,彼此间完成不同的工作,



      交替执行

      ,称为多线程




  • 线程的组成


    • CPU时间片





      操作系统(OS)


      会为每个线程分配执行时间


    • 运行数据



      • 堆空间:


        存储

        线程需使用的

        对象

        ,多个线程可以

        共享

        堆中的

        对象


      • 栈空间:


        存储

        线程需使用的

        局部变量

        ,每个线程都拥有

        独立

        的栈。

    • 线程的逻辑代码


  • 代码:
    package day19;
    public class TestThread{
     public static void main(String[] args){
      Task1 task1 = new Task1();
      Thread t1 = new Thread(task1);
      t1.start();
      
      Thread t2 = new TaskThread();  //Thread类实现了Runnable接口,本身可以充当线程的任务
      t2.start();
     }
    }
    class Task1 implements Runnable{
     public void run(){
      for(int i = 0; i < 10; i++){
       System.out.println("@@@ "+i);
      }
     }
    }
    class TaskThread extends Thread{
     public void run(){
      for(int i = 0; i < 10; i++){
       System.out.println("### "+i);
      }
     }
    }


  • 运行结果:

    在这里插入图片描述



02_Thread的基本状态




  • new 初始状态

    线程对象被创建,即为初始状态。在堆中开辟内存,与常规对象无异。




  • Ready 就绪状态

    调用start() 之后,进入就绪状态,等待OS选中,并分配时间片。




  • Running 运行状态

    获得时间片后,进入运行状态 ,如果时间片到期,则回到就绪状态。




  • Terminated 终止状态

    主线程main()或独立线程run()结束,进入终止状态,并释放持有的时间片。



  • 总结:
    • 实际上,


      就绪状态与运行状态统称为Runnable

    • 可通过设置线程的优先级,保证其执行的顺序:

      Thread t1 = new Thread(task1); t1.setPriority(10); //1~10优先级越来越高

      。但是由于Java的跨平台性,不同的操作系统会有不同的线程调度策略,对于其他操作系统优先级可能不会发挥作用。



03_线程的等待状态

- #####



  • 方法:


    • Thread.sleep()


      限时等待,线程进入休眠状态,会抛出**

      InterruptedException异常

      **。


    • Thread.yield()


      放弃CPU,回到就绪状态。


    • setDaemon(true)


      设置线程为

      守护线程

      ,不论该线程是否结束,当所有的非守护线程都结束时,进程就会结束。


    • t.join()


      当前线程进入

      等待状态

      ,直到

      t

      线程终止,才会恢复执行,


      会抛出异常




    • Thread.currentThread()


      获得当前线程


    • t.getName()


      获得

      t

      线程的名字(创建线程对象时可以传入一个字符串,当做线程的名字,否则取默认名字)


  • 代码:
    package day19;
    public class TestThread1{
     public static void main(String[] args){
      Thread t1 = new Thread(new TaskA());
      Thread t2 = new ThreadB();
      
      t2.setDaemon(true);
      t1.start();
      t2.start();
      
      /*
      t1.join();
      t2.join();
      System.out.println(Thread.currentThread().getName());
      System.out.println("All Thread is Over");
      */
     }
    }
    class TaskA implements Runnable{
     public void run(){
      for(int i = 1; i <= 10; i++){
       System.out.println(i);
       try{
        Thread.sleep(100);
       }catch(InterruptedException e){
        e.printStackTrace();
       }
      }
     }
    }
    class ThreadB extends Thread{
     public void run(){
      for(char c = 'A'; c <= 'N'; c++){
       System.out.println(c);
       System.out.println(Thread.currentThread().getName());
       try{
        Thread.sleep(500);
       }catch(InterruptedException e){
        e.printStackTrace();
       }
      }
     }
    }


  • 运行结果:

    在这里插入图片描述



04_线程安全的问题

  • 当多线程共同访问同一个对象(


    临界资源


    )的时候,如果破坏了不可分割的操作(


    原子操作


    ),就可能发生


    数据不一致




  • 代码:
    package day19;
    public class TestSynchronization{
     public static void main(String[] args) throws Exception{
      MyList list = new MyList();
      Thread t1 = new Thread(new Runnable(){
       public void run(){
        list.add("C");
       }
      });
      Thread t2 = new Thread(new Runnable(){
       public void run(){
        list.add("D");
       }
      });
      
      t1.start();
      t2.start();
      
      t1.join();
      t2.join();
      list.print();
     }
    }
    class MyList{
     String[] s = {"A","B","","","",""};
     int index = 2;
     
     public void add(String s1){
      s[index] = s1;
      try{
       Thread.sleep(100);
      }catch(InterruptedException e){
       e.printStackTrace();
      }
      index++;
     }
     public void print(){
      for(int i = 0; i < s.length; i++){
       System.out.println(s[i]);
      }
     }
    }


  • 运行结果:

    在这里插入图片描述



05_同步代码块

在这里插入图片描述

  • 每个Java对象都有一个互斥锁标记,用来分配给线程


  • synchronized(o){ //代码块 }




    对o对象加锁的

    同步代码块



    ,只有拿到o的


    锁标记


    的线程,才能进入对o加锁的同步代码块。


  • 修改上面代码为:
    synchronized(list){	
    	list.add("C");
    }
    
    synchronized(list){	
    	list.add("D");
    }


  • 运行结果:

    在这里插入图片描述



06_同步方法和死锁




  • synchronized


    方法修饰符

    ,表示对this加锁的同步代码块。只有拿到this的锁标记的线程,才能调用this的同步方法。



  • 修改上上代码为(结果正确):
    public synchronized void add(String s){	
    	//代码块
    }



07_等待-通知机制



  • 线程通信机制:



    等待-通知机制




  • o.wait():

    必须


    出现在对o加锁的同步代码块里


    ,执行后线程会

    释放锁标记



    进入等待状态(进入o的等待队列)




  • o.notify()/notifyAll():

    必须


    出现在对o加锁的同步代码块里


    ,执行后

    从等待状态(o的等待队列)中释放一个/全部线程



  • 代码:
    package day20;
    public class TestWaitNotify{
     public static void main(String[] args) throws Exception{
      Object o = new Object();
      
      Thread t = new Thread(new Runnable(){
       public void run(){
        synchronized(o){
         System.out.println("A");
         System.out.println("B");
         o.notify();
         System.out.println("C");
         System.out.println("D");
        }
       }
      });
      t.start();
      
      synchronized(o){
       System.out.println("1");
       System.out.println("2");
       o.wait();
       System.out.println("3");
       System.out.println("4");
      }
     }
    }


  • 运行结果:

    在这里插入图片描述



08_生产者消费者



  • 代码:
    package day20;
    public class TestProducerConsumer{
     public static void main(String[] args){
      MyStack stack = new MyStack();
      
      Runnable task1 = new Runnable(){
       public void run(){
        for(char c = 'A'; c <= 'I'; c++){
         stack.push(c+"");
        }
       }
      };
      Runnable task2 = new Runnable(){
       public void run(){
        for(int i = 1; i <= 9; i++){
         stack.pop();
        }
       }
      };
      new Thread(task1).start();
      //new Thread(task1).start();
      new Thread(task2).start();
      //new Thread(task2).start();
     }
    }
    class MyStack{
     String[] data = {"","","","","",""};
     int index;
     public synchronized void push(String s){
      while(index == data.length){
       try{
        this.wait();
       }catch(InterruptedException e){
        e.printStackTrace();
       }
      }
      data[index] = s;
      index++;
      System.out.print(s+" pushed ");
      print();
      this.notifyAll();
     }
     public synchronized void pop(){
      while(index == 0){
       try{
        this.wait();
      }catch(InterruptedException e){
       e.printStackTrace();
      }
      }
      index--;
      String s = data[index];
      data[index] = "";
      System.out.print(s+" poped  ");
      print();
      this.notifyAll();
     }
     public void print(){
      for(int i = 0; i < data.length; i++){
       System.out.print(data[i]+" ");
      }
      System.out.println();
     }
    }


  • 运行结果:

    在这里插入图片描述



09_数字和字母的交替打印



  • 代码:
    package day20;
    public class TestNumberCharPrint{
     public static void main(String[] args){
      Object o = new Object();
      Runnable task1 = new Runnable(){
       public void run(){
        synchronized(o){
         for(int i = 1; i <= 10; i++){
          System.out.println(i);
          if(i % 2 == 0){
           o.notifyAll();
           try{
            if(i != 10) o.wait();
           }catch(InterruptedException e){
            e.printStackTrace();
           }
          }
         }
        }
        
       }
      };
      Runnable task2 = new Runnable(){
       public void run(){
        synchronized(o){
         for(char c = 'A'; c <= 'E'; c++){
          System.out.println(c);
          o.notifyAll();
          try{
           if(c != 'E') o.wait();
          }catch(InterruptedException e){
           e.printStackTrace();
          }
         }
        }
        
       }
      };
      Thread t1 = new Thread(task1);
      Thread t2 = new Thread(task2);
      t1.start();
      t2.start();
     }
    }


  • 运行结果:

    在这里插入图片描述



10_线程池



  • 代码:
    package day20;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class TestExecutor{
     public static void main(String[] args){
      ExecutorService es = Executors.newFixedThreadPool(2);
      //ExecutorService es = Executors.newCachedThreadPool();
      Runnable r1 = new Runnable(){
       public void run(){
        for(int i = 0; i < 10; i++){
         System.out.println("### "+i);
         try{
          Thread.sleep(100);
         }catch(InterruptedException e){
          e.printStackTrace();
         }
        }
       }
      };  
      Runnable r2 = new Runnable(){
       public void run(){
        for(int i = 0; i < 10; i++){
         System.out.println("@@@ "+i);
         try{
          Thread.sleep(100);
         }catch(InterruptedException e){
          e.printStackTrace();
         }
        }
       }
      };
      Runnable r3 = new Runnable(){
       public void run(){
        for(int i = 0; i < 10; i++){
         System.out.println("$$$ "+i);
         try{
          Thread.sleep(100);
         }catch(InterruptedException e){
          e.printStackTrace();
         }
        }
       }
      };
      es.submit(r1);
      es.submit(r2);
      es.submit(r3);
      es.shutdown();
     }
    }


  • 运行结果:

    在这里插入图片描述



11_Callable和Future



  • 代码:
    package day20;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Callable;
    import java.util.concurrent.Future;
    public class TestCallable{
     public static void main(String[] args) throws Exception{
      ExecutorService es = Executors.newCachedThreadPool();
      
      Callable<Integer> task1 = new Callable<Integer>(){
       public Integer call() throws Exception{
        System.out.println("task1 starts");
        int result = 0;
        for(int i = 1; i < 100; i += 2){
         result += i;
         Thread.sleep(100);
        }
        System.out.println("task1 ends");
        return result;
       }
      };
      Callable<Integer> task2 = new Callable<Integer>(){
       public Integer call() throws Exception{
        System.out.println("task2 starts");
        int result = 0;
        for(int i = 2; i <= 100; i += 2){
         result += i;
         Thread.sleep(100);
        }
        System.out.println("task2 ends");
        return result;
       }
      };
      
      Future<Integer> f1 = es.submit(task1);
      Future<Integer> f2 = es.submit(task2);
      System.out.println("main do sth");
      int result = f1.get()+f2.get();
      System.out.println(result);
      
      es.shutdown();
     }
    }


  • 运行结果:

    在这里插入图片描述



12_Lock对象



  • Lock接口

    • JDK5

      加入,与synchronized比较,显示定义,结构更灵活。
    • 提供更多实用性方法,功能更强大、性能更优越。

    • 常用方法:



      1. void lock():


        //获取锁,如锁被占用,则等待。


      2. boolean tryLock():


        //尝试获取锁(成功返回true,失败返回false,不阻塞)


      3. void unlock():


        //释放锁


  • 代码:
    package day20;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    public class TestLock{
     public static void main(String[] args) throws Exception{
      MyList list = new MyList();
      Thread t1 = new Thread(new Runnable(){
       public void run(){
        list.add("C");
       }
      });
      Thread t2 = new Thread(new Runnable(){
       public void run(){
        list.add("D");
       }
      });
      
      t1.start();
      t2.start();
      
      t1.join();
      t2.join();
      list.print();
     }
    }
    class MyList{
     String[] s = {"A","B","","","",""};
     int index = 2;
     Lock lock = new ReentrantLock();
     
     public void add(String s1){
      try{
       //lock.tryLock();
       lock.lock();
       s[index] = s1;
       try{
        Thread.sleep(100);
       }catch(InterruptedException e){
        e.printStackTrace();
       }
       index++;
      }
      finally{
       lock.unlock();
      }
     }
     public void print(){
      for(int i = 0; i < s.length; i++){
       System.out.println(s[i]);
      }
     }
    }


  • 运行结果:

    在这里插入图片描述



13_Condition对象



  • 代码:
    package day20;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    public class TestProducerConsumerLock{
     public static void main(String[] args){
      MyStack stack = new MyStack();
      
      Runnable task1 = new Runnable(){
       public void run(){
        for(char c = 'A'; c <= 'I'; c++){
         stack.push(c+"");
        }
       }
      };
      Runnable task2 = new Runnable(){
       public void run(){
        for(int i = 1; i <= 9; i++){
         stack.pop();
        }
       }
      };
      new Thread(task1).start();
      //new Thread(task1).start();
      new Thread(task2).start();
      //new Thread(task2).start();
     }
    }
    class MyStack{
     String[] data = {"","","","","",""};
     int index;
     Lock lock = new ReentrantLock();
     Condition full = lock.newCondition();
     Condition empty = lock.newCondition();
     
     public void push(String s){
      try{
       lock.lock();
       while(index == data.length){
        try{
         full.await();
        }catch(InterruptedException e){
         e.printStackTrace();
        }
       }
       data[index] = s;
       index++;
       System.out.print(s+" pushed ");
       print();
       empty.signalAll();
      }
      finally{
       lock.unlock();
      }
     }
     public void pop(){
      try{
       lock.lock();
       while(index == 0){
        try{
         empty.await();
       }catch(InterruptedException e){
        e.printStackTrace();
       }
       }
       index--;
       String s = data[index];
       data[index] = "";
       System.out.print(s+" poped  ");
       print();
       full.signalAll();
      }
      finally{
       lock.unlock();
      }
     }
     public void print(){
      for(int i = 0; i < data.length; i++){
       System.out.print(data[i]+" ");
      }
      System.out.println();
     }
    }


  • 运行结果:

    在这里插入图片描述



版权声明:本文为m0_45044194原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。