美文网首页
JavaSE学习笔记——多线程

JavaSE学习笔记——多线程

作者: funOfFan | 来源:发表于2020-03-06 16:42 被阅读0次
    • 理解程序、进程、线程的概念

      1. 程序可以理解为静态的代码
      2. 进程可以理解为执行中的程序
      3. 线程是进程的进一步细分,理解为程序的一条执行路劲
    • 如何创建Java程序的线程

      1. 通过继承的方式创建多进程
      //1. 创建一个继承自Thread的子类
      class SubThread extends Thread{
          //2.重写run方法,方法内实现此子线程要完成的工作
          public void run(){
              for (int i = 0; i <= 100 ; i++) {
                  System.out.println(Thread.currentThread().getName() +":"
                          + Thread.currentThread().getPriority() +":"+i);
              }
          }
      }
      public class TestThread {
          public static void main(String[] args) {
              //3.创建一个子类的对象
              SubThread st1 = new SubThread();
              //4.调用线程的start方法,启动此线程;JVM调用相应的run方法
              //一个线程只能调用一次start方法
              st1.start();
              //不能通过Thread实现类对象的run方法去启动一个线程,必须start
          }
      }
      
      1. 通过实现Runnable接口的方式来实现多线程
      class PrintNum implements Runnable{
          //2. 实现Runnable接口中的抽象方法
          public void run(){
              //子线程执行的代码
              for (int i = 0; i <= 100 ; i++) {
                  if(i % 2 == 0){
                      System.out.println(Thread.currentThread().getName() +
                              " : " + i);
                  }
              }
          }
      }
      
      1. Thread类本身实际上也是实现了Runnable接口的一个实现类。一般来说,
        采用实现的方式更好,因为这样可以避开单继承的局限性。
        如果多个线程有共享数据的话,更适合使用实现Runnable接口的方式,同时,
        共享数据所在的类,可以作为Runnable接口的实现类。
    • 常用Thread类方法

        start()     run()                   currentThread()
        
        getName()   setName(String name)
        
        yield()     sleep()                 isAlive() 
        
        notify()    notifyALl() 
        getPriority()                       setPriority(int i)
      
    • 使用多线程的优点
      1.提高应用程序的响应,对图形化界面更有意义
      2.提高计算机系统CPU的利用率
      3.改善程序结构,将既长又复杂的进程分为多个线程,独立运行,利于理解和修改

    • 线程分类:
      1.守护线程:如Java垃圾回收,若JVM中都是守护线程,当前JVM将退出

      2.用户线程:在start()之前,调用Thread.setDaemon(),可将用户线程转为守护线程

    • 线程的生命周期

      1. 新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
      2. 就绪:处于新建状态的线程被start()之后,将进入线程队列等待CPU时间片,此时已具备运行条件
      3. 运行:就绪线程被调度并获得处理器资源时,编进入运行状态,run()方法定义了线程的操作和功能
      4. 阻塞:被人为挂起或进行IO时,让出CPU并临时中止自己的执行,进入阻塞状态
      5. 死亡:线程完成了它的全部工作或线程被提前强制性地中止
    • 线程的同步机制

      1. 如果我们创建的多个线程之间,存在着共享数据,就有可能出现线程安全问题。
        当其中一个线程操作共享数据,但操作尚未完成的时候,另外的线程就参与进来,
        这就会导致线程安全问题。
      2. 解决线程安全问题的方法在于,只有当前线程完全操作完共享数据之后,
        其他线程才可以操作共享数据。
        • 方式一:同步代码块
          synchronized(同步监视器){
              //操作共享数据的代码
              //同步监视器,也叫锁,任何一个类的对象都可以来充当锁
              //要想保证线程的安全,必须要求所有的线程公用同一把锁。
              //使用实现Run able接口的方式创建接口的话,同步代码块中的锁
              //可以考虑使用this对象
              //如果使用继承的方法实现多线程,一般不要使用this对象作为锁
              //共享数据:多个线程需要共同操作的变量,明确哪部分是操作共享数据的代码
          }
          
        • 方式二:同步方法,将操作共享数据的方法声明为synchronized
          public synchronized void show(){
              //对于非静态的方法而言,使用同步的话,默认锁为this,
              //如果使用继承的方式使用多线程的话,就要慎用同步方法(默认this锁)
              //对于静态的方法如果使用同步,默认的锁为当前类本身
          }
          
      3. 引起锁释放的操作:
        • 当前线程的同步方法、同步代码块执行结束
        • 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行
        • 当前线程在同步代码块、同步方法中出现了未处理的Error、Exception,导致异常结束
        • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
          。需要注意的是,sleep方法并不会导致锁释放,yield方法也不会释放锁。
      4. 死锁:不同线程分别占用对方所需要的同步资源不放弃,都在等待对方放弃自己所需的同步资源,
        就形成了线程的死锁。
    • 线程通信

      1. wait():当在同步中执行到此方法,则线程必须等待,直至其他线程执行notify()方法将其唤醒。
        唤醒后,继续wait方法后的代码。
      2. notify() notifyAll():在同步中执行到此方法,则唤醒其他被wait的一个或者所有的线程。
      3. 上述三个方法必须使用在同步代码块或者同步方法中
      4. 两个线程交替打印1-100的数字
        class PrintNumber implements Runnable {
            int num = 1;
        
            public void run() {
                while (true) {
                    synchronized (this) {
                        notify();
                        if (num <= 100) {
                            try {
                                Thread.currentThread().sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(Thread.currentThread().getName() +
                                    " : " + num);
                            num++;
                        } else
                            break;
                        try {
                            wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
        public class TestCommunication {
            public static void main(String[] args) {
                PrintNumber p = new PrintNumber();
                Thread t1 = new Thread(p);
                Thread t2 = new Thread(p);
                t1.setName("A");
                t2.setName("B");
                t1.start();
                t2.start();
            }
        }
        
      5. 生产者消费者问题
        class Clerk {
            int product;
        
            //生产产品
            public synchronized void addProduct() {
                if(product >= 20){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    product++;
                    System.out.println(Thread.currentThread().getName()
                    + ":生产了第" + product + "个产品");
                    notifyAll();
                }
            }
        
            //消费产品
            public synchronized void consumeProduct(){
                if(product <= 0){
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    System.out.println(Thread.currentThread().getName()
                            + ":消费了第" + product + "个产品");
                    product--;
                    notifyAll();
                }
            }
        }
        
        class Producer implements Runnable {
            Clerk clerk;
        
            public Producer(Clerk clerk) {
                this.clerk = clerk;
            }
        
            public void run() {
                System.out.println("生产者开始生产");
                while (true) {
                    clerk.addProduct();
                }
            }
        }
        
        class Consumer implements Runnable {
            Clerk clerk;
        
            public Consumer(Clerk clerk) {
                this.clerk = clerk;
            }
        
            public void run() {
                System.out.println("消费者消费产品");
                while(true){
                    clerk.consumeProduct();
                }
            }
        }
        
        public class TestProduceConsume {
            public static void main(String[] args) {
                Clerk clerk = new Clerk();
                Producer p1 = new Producer(clerk);
                Consumer c1 = new Consumer(clerk);
                Thread tp = new Thread(p1);
                Thread tc = new Thread(c1);
        
                tp.setName("生产者");
                tc.setName("消费者");
                tp.start();
                tc.start();
            }
        }
        

    相关文章

      网友评论

          本文标题:JavaSE学习笔记——多线程

          本文链接:https://www.haomeiwen.com/subject/nghwrhtx.html