zoukankan      html  css  js  c++  java
  • 多线程基础

    线程的创建

    继承Thread

    public class MyThread extends Thread{
      @Override
      public void run(){
        for(int i = 0; i < 10; i++{
          System.out.println(Thread.currentThread().getName());
        }
      }
    }
    
    pulbic class Test{
      public static void main(String[] args){
        MyThread tt = new TestThread();
        Thread t = new Thread(tt);
        t.start();    
      }
    }

    实现Runnable接口

    public class MyThread implements Runnable{
      @Override
      public void run(){
        for(int i = 0; i < 10; i++{
          System.out.println(Thread.currentThread().getName());
        }
      }
    }
    
    pulbic class Test{
      public static void main(String[] args){
        MyThread tt = new TestThread();
        Thread t = new Thread(tt);
        t.start();    
      }
    }

    实现Callable接口

    public class TestRandomNum implements Callable<Integer>{
      @Override
      public Integer call() throws Exception{
        return new Random().nextInt(10);// 返回10以内的随机数
      }
    }
    
    public class Test{
      public static void main(String[] args){
        TestRandomNum trn = new TestRandomNum();
        FutureTask ft = new FutureTask(trn);
        Thread t = new Thread(ft);
        t.start();
        Object obj = ft.get();
        System.out.println(obj);
      }
    }

    线程的生命周期

    五态模型

    线程常见方法

    start()

    启动当前线程,表面上调用start方法,实际在调用线程中的run方法

    run()

    线程类 继承thread类 或者 实现Runnable接口的时候,都要重新实现run方法

    run方法里面就是线程要执行的内容

    currentThread()

    Thread类中的一个静态方法,获取当前正在执行的线程

    setName()

    设置线程名字

    getName()

    读取线程名字

    级别

    同优先级别的线程,采取的策略就是FCFS,使用时间片策略

    如果优先级别高,被CPU调度的概率就高

    • 1,最小
    • 5,普通
    • 10,最大

    设置优先级

    public class TestThread01 extends Thread{
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          System.out.println(i);
        }
      }
    }
    
    public class TestThread02 extends Thread{
      @Override
      public void run(){
        for(int i = 20; i <= 30; i++){
          System.out.println(i);
        }
      }
    }
    
    class Test{
      public static void main(String[] args){
        // 两个线程抢夺CPU, 可以通过设置优先级来调整
        // 数字越小, 优先级越低
    
        TestThread01 t1 = new TestThread01();
        t1.setPriority(10);
        t1.start();
    
        TestThread01 t2 = new TestThread02();
        t1.setPriority(1);
        t2.start();
      }
    
    }

    join方法

    当一个线程调用了join方法,这个线程会被先执行,结束后执行其他线程

    必须先start,join才能生效

    public class TestThread extends Thread{
      public TestThread(String name){
        super(name);
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          System.out.println(i);
        }
      }
    }
    
    class Test{
      public static void main(String[] args){
        for(int i = 1; i <= 100; i++){
          System.out.println("main..." + i);
          if(i == 6){
            // 创建子线程:
            TestThread tt = new TestThread("子线程");
            tt.start();
            tt.join();
          }      
      }
    }

    sleep方法

    人为阻塞

    public class Test{
      public static void main(String[] args){
        Thread.sleep(10);// ms
        System.out.println(".....");
      }
    }

    setDaemon方法

    设置伴随线程,将子线程设置为主线程的伴随线程,主线程停止的时候,子线程也不继续执行了

    public class Test{
      public void run(String[] args){
        for(int i = 1; i <= 1000; i++){
          System.out.println(".....");
        }    
      }
    }
    
    public class TestThread extends Thread{
      public static void main(String[] args){
        TestThread tt = new TestThread();
        tt.setDaemon(true);// 设置伴随线程, 注意: 先设置, 再启动
        tt.start();
    
        for(int i = 1; i <= 10; i++){
          System.out.println("main...." + i);
        }
      }
    }

    stop方法

    public class Demo{
      public static void main(String[] args){
        for(int i = 1; i <= 100; i++){
          if(i == 6){
            Thread.currentThread().stop();// 过期方法, 不建议使用
          }
          System.out.println(i);
        }    
      }
    }

    线程安全

    本质上是线程同步问题,需要加锁和同步监视器

    public class MyThread implements Runnable{
      int num = 0;
      @Override
      public void run(){
        for(int i = 0; i <= 100; i++){
          synchronized(this){
            if(num > 0){
              // coding
            }
          }
        }
      }
    }

    synchronized关键字就是一个普通的排他锁(mutex)

    synchronized就是对mutex=1的锁使用pv操作

    public class MyThread implements Runnable{
      int num = 0;
      @Override
      public void run(){
        for(int i = 0; i <= 100; i++){
          synchronized(this){
            if(num > 0){
              // coding
            }
          }
        }
      }
    }

    尽量不要用String和Integer做同步监视器

    建议使用final关键字修饰同步监视器(final只是锁定了地址值)

    同步就是pv操作

    同步代码块可以发生CPU的切换,但是其他线程无法执行同步代码块

    同步代码块--临界区

    同步方法

    public class MyThread implements Runnable{
      int num = 0;
      @Override
      public static synchronized void do(){
      for(int i = 0; i <= 100; i++){
        if(num > 0){
          // coding
        }      
      }
    }

    不要将run方法定义为同步方法

    非静态同步方法同步监视器是this

    静态同步方法同步监视器是字节码信息

    同步方法的锁是this,同步代码块将线程挡在代码块之外,在方法内部

    效率:同步代码块 > 同步方法

    Lock锁

    lock是一个api,多态

    public MyThreaqd implements Runnable{
      int num = 0;
      Lock lock = new ReentrantLock();
      @Override
      public void run(){
        for(int i = 1; i <= 100; i++){
          lock.lock();
          try{
            if(num > 0){
              System.out.println(Thread.currentThread().getName());
            }
          }catch(Exception ex){
            ex.printStackTrace();
          }finally{
            lock.unlock();
          }      
        }
      }
    }

    使用顺序

    Lock > synchronized > 同步代码块

    Lock和synchronized的区别

    • Lock是显式锁,synchronized是隐式锁
    • Lock只有代码块锁,synchronized有代码块锁和方法锁
    • 使用Lock锁,Jvm花费较少时间调度线程,性能更好,有更好的拓展性(提供更多原子类)

    线程同步的缺点

    • 线程安全,效率低
    • 线程不安全,效率高

    可能造成死锁

    死锁,四个必要条件,两个充分条件

    笔记地址:https://github.com/YC-L/Postgraduate-examination/blob/Operating-System/process-management/%E6%AD%BB%E9%94%81/%E6%AD%BB%E9%94%81.md

    线程通信

    利用同步代码块解决数据错乱

    public class ProducerThread extends Thread{
      // 共享商品
      private Product p;
    
      public ProducerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          synchronized(p){
            if(i % 2 == 0){        
              p.setBrand("");
              try{
                Thread.sleep(100);
              }catch(InterruptedException e){
                e.printStackTrace();
              }        
              p.setName("");
            }else{
              p.setBrand("");
              try{
                Thread.sleep(100);
              }catch(InterruptedException e){
                e.printStackTrace();
              }
              p.setName("");
            }
          }      
        }
      }
    }
    
    public class CustomerThread extends Thread{
      // 共享商品
      private Product p;
    
      public CustomerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          synchronized(p){
            // coding
          }
        }
      }
    }
    
    public class Test{
      public static void main(String[] args){
        Product p = new Product();
        ProducerThread pt = new ProducerThread();
        CustomerThread ct = new CustomerThread();
    
        pt.start();
        ct.start();
      }
    }

    利用同步方法解决问题

    public class Product{
      public synchronized void setProduct(String brand, String name){
        this.setBrand(brand);
        try{
          Thread.sleep(100);
        }catch(InterruptedException e){
          e.printStackTrace();
        }
        this.setName();
      }
    
      public synchronized void getProduct(){
        // coding
      }
    }
    
    public class ProducerThread extends Thread{
      // 共享商品
      private Product p;
    
      public ProducerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          if(i % 2 == 0){        
            p.setProduct("", "");
          }       
        }
      }
    }
    
    public class CustomerThread extends Thread{
      // 共享商品
      private Product p;
    
      public CustomerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          p.getProduct(); 
        }
      }
    }
    
    public class Test{
      public static void main(String[] args){
        Product p = new Product();
        ProducerThread pt = new ProducerThread();
        CustomerThread ct = new CustomerThread();
    
        pt.start();
        ct.start();
      }
    }

    生产消费交替执行

    添加一个标志位

    public class Product{
    
      boolean flag = false;
    
      public synchronized void setProduct(String brand, String name){
        if(flag == true){
          try{
            wait();
          }catch(InterruptedException e){
            e.printStackTrace();
          }
        }else{
          this.setBrand(brand);
          try{
            Thread.sleep(100);
          }catch(InterruptedException e){
            e.printStackTrace();
          }
          this.setName();
          flag = true;
          notify();
        }   
      }
    
      public synchronized void getProduct(){
        if(!flag){
          try{
            wait();
          }catch(InterruptedException e){
            e.printStackTrace();
          }
        }
        // coding
        flag = false;
        notify();
      }
    }
    
    public class ProducerThread extends Thread{
      // 共享商品
      private Product p;
    
      public ProducerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          if(i % 2 == 0){        
            p.setProduct("", "");
          }else{
            p.setProduct("", "");
          }       
        }
      }
    }
    
    public class CustomerThread extends Thread{
      // 共享商品
      private Product p;
    
      public CustomerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          p.getProduct(); 
        }
      }
    }
    
    public class Test{
      public static void main(String[] args){
        Product p = new Product();
        ProducerThread pt = new ProducerThread();
        CustomerThread ct = new CustomerThread();
    
        pt.start();
        ct.start();
      }
    }

    锁池

    synchronized

    等待池

    wait(),notify(),notifyAll()

    当一个线程调用了某个对象的wait方法,该线程进入该对象的等待池(并已将锁释放)

    如果之后,其他线程调用了notify或者notifyAll

    该等待池中的线程会唤起,进入对象的锁池获取该锁,获得锁成功,线程沿着wait方法的路径继续执行

    Lock锁情况下的线程通信

    public class Product{
    
      boolean flag = false;
    
      Lock lock = new ReentrantLock();
    
      Condition produceCondition = lock.newCondition();
    
      Condition consumeCondition = lock.newCondition();
    
      public void setProduct(String brand, String name){
        lock.lock();
        try{
          if(flag == true){
          try{
            // 生产者阻塞, 生产者进入等待队列中
            produceCondition.await();
          }catch(InterruptedException e){
            e.printStackTrace();
          }
        }else{
          this.setBrand(brand);
          try{
            Thread.sleep(100);
          }catch(InterruptedException e){
            e.printStackTrace();
          }
          this.setName();
          flag = true;
          consumeCondition.signal();
        }finally{
          lock.unlock();
        }    
      }
    
      public void getProduct(){
        lock.lock();
        try{
          if(!flag){
            try{
              consumeCondition.await();
            }catch(InterruptedException e){
              e.printStackTrace();
            }
          }
          // coding
          flag = false;
          produceCondition.signal();
        }finally{
          lock.unlock();
        }    
      }
    }
    
    public class ProducerThread extends Thread{
      // 共享商品
      private Product p;
    
      public ProducerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          if(i % 2 == 0){        
            p.setProduct("", "");
          }else{
            p.setProduct("", "");
          }       
        }
      }
    }
    
    public class CustomerThread extends Thread{
      // 共享商品
      private Product p;
    
      public CustomerThread(Product p) {
        this.p = p;
      }
      @Override
      public void run(){
        for(int i = 1; i <= 10; i++){
          p.getProduct(); 
        }
      }
    }
    
    public class Test{
      public static void main(String[] args){
        Product p = new Product();
        ProducerThread pt = new ProducerThread();
        CustomerThread ct = new CustomerThread();
    
        pt.start();
        ct.start();
      }
    }

    Condition是在jdk1.5之后出现的,用来替代传统的await和notify

    可以使用多个锁池和多个锁

    论读书
    睁开眼,书在面前
    闭上眼,书在心里
  • 相关阅读:
    题解 AT5228 【[ABC162A] Lucky 7】
    题解 P6467 【[COCI2008-2009#6] BUKA】
    2020 Codeforces 愚人节比赛题解 A~D
    题解 AT4251 【[ABC110A] Maximize the Formula】
    题解 AT5638 【November 30】
    题解 AT4164 【[ABC102A] Multiple of 2 and N】
    多项式全家桶
    烂题推荐
    NOIP 2020 游记
    P5048 题解
  • 原文地址:https://www.cnblogs.com/YC-L/p/14422873.html
Copyright © 2011-2022 走看看