zoukankan      html  css  js  c++  java
  • 黑马程序员_java基础笔记(04)...多线程

    ——————————ASP.Net+Android+IOS开发.Net培训、期待与您交流!——————————

    多线程。第一重点:创建线程的两种方式。第二重点:同步的所有特性   
     
    进程:正在执行的程序。
    线程:是进程中用于控制程序执行的控制单元(执行路径,执行情景)进程中至少有一个线程。
    对于JVM,启动时,有两个线程:jvm的主线程。jvm的垃圾回收线程。
     
    第一重点:创建线程的两种方式
      如何在程序中自定义线程?
      Java给我们提供了对象线程这类事物的描述。该类是Thread
    该类中定义了,
      创建线程对象的方法(构造函数).
      提供了要被线程执行的代码存储的位置run()
      开启线程运行的方法start()
      还有一些其他的方法用于操作线程:
        static Thread currentThead()  //获取当前线程对象。
        getName(): //返回该线程的名称。
        static void sleep(time)throws InterruptedException:
        join()方法//等待该线程终止。
     
     
    创建线程的第一种方式是:继承Thread类。
      原因:要覆盖run方法,定义线程要运行的代码。
      步骤:
        1,继承Thread类。
        2,覆盖run方法。将线程要运行的代码定义其中。
        3,创建Thread类的子类对象,其实就是在创建线程,调用start方法。
    示例:多个窗口同时买票 1,继承Thread类
    class Ticket  extends Thread  {
      // static 让四个卖票窗口共享100票
      private static  int tick = 100;
      // 覆盖run方法
      public void run(){
       while(true){
        if(tick>0){
         System.out.println(Thread.currentThread().getName()+"....sale : "+ tick——);
        }
       }
      }
    }
    class  TicketDemo{
      public static void main(String[] args) {
        Ticket t1 = new Ticket(); 
        Ticket t2 = new Ticket(); 
        Ticket t3 = new Ticket(); 
        Ticket t4 = new Ticket(); 
        //调用start方法
        t1.start();
        t2.start();
        t3.start();
        t4.start();
      }
    }
     
    创建线程的第二种方式:实现Runnable接口。
     
      如果自定义类中有多线程要运行的代码。但是该类有自己的父类。那么就不可以在继承Thread。Java给我们提供了一个规则。Runnable接口。
     
    如果自定义类不继承Thread,也可以实现Runnable接口。并将多线程要运行的代码存放在Runnable的run方法中。这样多线程也可以帮助该类运行。这样的操作有一个好处:避免了单继承的局限性。
     
    步骤:
      1,定义了实现Runnable接口。
      2,覆盖接口的run方法。将多线程要运行的代码存入其中。
      3,创建Thread类的对象(创建线程),并将Runnable接口的子类对象作为参数传递给Thread的构造函数。因为线程要运行的代码都在Runnable子类的run方法中存储。所以要将该run方法所属的对象传递给Thread。让Thread线程去使用该对象调用其run方法。
      4,调用Thread对象的start方法。开启线程。
     实现方式好处:避免了单继承的局限性。
    实现方式和继承方式区别?
      继承Thread:线程代码存放Thread子类run方法中。
      实现Runnable,线程代码存在接口的子类的run方法。
     
    示例:多个窗口同时买票 2 ,实现Runnable接口。
    class Ticket implements Runnable{
      private  int tick = 100;
      // 覆盖run方法
      public void run(){
        while(true){
          if(tick>0){
            System.out.println(Thread.currentThread().getName()+"....sale : "+ tick——);
          }
        }
      }
    }
    class  TicketDemo{
      public static void main(String[] args) {
        Ticket t = new Ticket();
        Thread t1 = new Thread(t);  //创建了一个线程;
        Thread t2 = new Thread(t);  //创建了一个线程;
        Thread t3 = new Thread(t);  //创建了一个线程;
        Thread t4 = new Thread(t);  //创建了一个线程;
        t1.start();
        t2.start();
        t3.start();
        t4.start();
      }
    }
     
    第二重点:同步的所有特性   
     
    线程的状态。
      1,被创建。
      2,运行。
      3,冻结。
        冻结状态的特点:放弃了执行资格。
        ①,sleep(time) 当sleep时间到就又开始运行
        ②,wait() 当调用notify()时线程开始运行
      4,消亡。
      5,还有一种特殊的状态:临时状态。
           该临时状态的特点:
             具备了执行资格,但不具备执行权,多线程具备随机性。因为是由cpu不断的快速切换造成的。就有可能会产生多线程的安全问题
    问题的产生的原因
    几个关键点:
      1,多线程代码中有操作共享数据。
      2,多条语句操作该共享数据。
    当具备两个关键点时,有一个线程对多条操作共享数据的代码执行的一部分。还没有执行完,另一个线程开始参与执行。就会发生数据错误。
    解决方法:
      当一个线程在执行多条操作共享数据代码时,其他线程即使获取了执行权,也不可以参与操作。
     
    Java对于多线程的安全问题提供了专业的解决方式。就是同步代码块。
    同步的原理:就是将部分操作功能数据的代码进行加锁。
    同步的表现形式:
      1,同步代码块。
        synchronized(对象)
        {
          需要被同步的代码
        }
        对象如同锁。持有锁的线程可以在同步中执行。
      2,同步函数。
        两者的不同:
          同步代码块使用的锁是任意对象。
          同步函数使用的锁是this。
          注意:对于static的同步函数,使用的锁不是this。是 类名.Class 是该类的字节码文件对象。
    涉及到了单例设计模式的懒汉式。
    单例设计模式的懒汉式
    class Single{
      private static Single s = null;
      private Single(){ }
      public static  Single getInstance(){
        if(s==null){
          synchronized(Single.class){
            if(s==null)
            s = new Single();
          }
        }
        return s;
      }
    }
     
    同步的好处:解决了线程的安全问题。
    弊端:
      较为消耗资源。同步嵌套后,容易死锁。
    要记住:同步使用的前提:
      1,必须是两个或者两个以上的线程。
      2,必须是多个线程使用同一个锁。
    这是才可以称为这些线程被同步了。
     
    停止线程:
    原理:run方法结束。run方法中通常定义循环,指定控制住循环线程即可结束
       1,定义结束标记。
       2,当线程处于了冻结状态,没有执行标记,程序一样无法结束。这时可以循环,正常退出冻结状态,或者强制结束冻结状态。
     
    强制结束冻结状态:interrupt();目的是线程强制从冻结状态恢复到运行状态。但是会发生InterruptedException异常
     
    线程中一些常见方法:
      setDaemon(boolean):将线程标记为后台线程,后台线程和前台线程一样,开启,一样抢执行权运行,只有在结束时,有区别,当前台线程都运行结束后,后台线程会自动结束。
      join():等待该线程结束。当A线程执行到了B的.join方法时,A就会处于冻结状态。A什么时候运行?当B运行结束后,A就会具备运行资格,继续运行。加入线程,可以完成对某个线程的临时加入执行。
     
    线程间通信。
      等待/唤醒机制
        也就是常见的生产者消费者问题。
      1.当多个生产者消费者出现时,需要让获取执行权的线程判断标记。通过while完成。
      2.需要将对方的线程唤醒。仅仅用notify,是不可以的。因为有可能出现只唤醒本方。有可能会导致,所有线程都等待。所以可以通过notifyAll的形式来完成 。

      wait():释放cpu执行权,释放锁。
      sleep():释放cpu执行权,不释放锁

     
    JDK1.5版本提供了一些新的对象,优化了等待唤醒机制。
      1,将synchronized 替换成了Lock接口。将隐式锁,升级成了显示锁。
        获取锁:lock();
        释放锁:unlock();注意:释放的动作一定要执行,所以通常定义在finally中。
        获取Condition对象:newCondition();
      2,将Object中的wait,notify,notifyAll方法都替换成了Condition的await,signal,signalAll。和以前不同是:一个同步代码块具备一个锁,该所以具备自己的独立wait和notify方法。现在是将wait,notify等方法,封装进一个特有的对象Condition,而一个Lock锁上可以有多个Condition对象。
     
     
    死锁。同步中嵌套同步。
    class Ticket implements Runnable{
      private  int tick = 1000;
      Object obj = new Object();
      boolean flag = true;
      public  void run(){
        if(flag){
          while(true){
            synchronized(obj){
               show();
            }
          }
        }
        else
        while(true)
        show();
      }
      public synchronized void show()//this{
        synchronized(obj){
          if(tick>0){
            try{Thread.sleep(10);}catch(Exception e){}
            System.out.println(Thread.currentThread().getName()+"....code : "+ tick——);
          }
        }
      }
    }
    class  DeadLock{
      public static void main(String[] args) {
        Ticket t = new Ticket();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        t1.start();
        try{Thread.sleep(10);}catch(Exception e){}
        t.flag = false;
        t2.start();
      }
    }

    线程类的其他方法
    setPriority(int num)
    setDaemon(boolean b)
    join()
    toString()

     
    —————————— ASP.Net+Android+IOS开发.Net培训、期待与您交流!—————————— ——————————
     详细请查看:http://edu.csdn.net 
  • 相关阅读:
    Notes about "Exploring Expect"
    Reuse Sonar Checkstyle Violation Report for Custom Data Analysis
    Eclipse带参数调试的方法
    MIT Scheme Development on Ubuntu
    Manage Historical Snapshots in Sonarqube
    U盘自动弹出脚本
    hg的常用配置
    Java程序员的推荐阅读书籍
    使用shared memory 计算矩阵乘法 (其实并没有加速多少)
    CUDA 笔记
  • 原文地址:https://www.cnblogs.com/In-order-to-tomorrow/p/3528527.html
Copyright © 2011-2022 走看看