• 黑马程序员__线程


    1.

    进程:正在执行中的程序

    线程:进程中一个独立的控制单元。  线程在控制进程的执行

    一个进程中至少有一个线程。

    主线程: JVM启动的时候会产生一个进程 java.exe,该进程中至少有一个线程负责java进程的执行,这个线程的代码存在于main方法中,称之为主线程。

    JVM启动时,还会有负责垃圾回收的线程。

    2.创建新线程有两种方法:

    一种是将类声明为 Thread 的子类,并重写子类的 run 方法,分配并启动该子类的实例。

    步骤:

    定义类继承Thread

    复写Thread类中的run方法。(将自定义的代码存储在run方法中,让线程运行)

    调用线程的 start 方法。  (该方法启动线程,通过调用run) 

    3.为什么要覆盖 run()

    Thread 用于描述线程,该类定义了一个函数,用于存储线程要运行的代码。该存储功能就是 run 方法。

    start();  //开启线程并执行线程的run方法

    run(); // 仅仅调用方法,线程创建了但没有运行

    4.线程的运行状态:

    5.线程名字获取

    System.out.println(Thread.currentThread().getName());     //main

    static Thread  currentThread()   返回当前线程对象的引用

    getName()  获取线程名称

    setName() 或重写构造函数   改变线程名称

    6  .创建线程的第2种方式是声明实现 Runnable 接口:

    定义一个类,实现Runnable 接口

    覆盖Runnable接口中的 run 方法

    建立Thread类对象, 将Runnable的子类实例作为实际参数传递给Thread类的构造函数

    调用Thread实对象的 start() 方法执行线程

    实现方式与继承方式的区别:

    实现方式:避免了单继承的局限性,  定义线程时,建议使用此方式

    实现方式 线程代码存放在接口的子类的run方法中

    继承方式 线程代码存放在Thread子类的run方法中

    class Thread2 implements Runnable
    {
        private int ticket = 30;
        public void run()
        {
            while(ticket>0)
            {
                if(ticket>0)
                    System.out.println("tickete="+ticket--);            
            }
        }
    }
    
    class Main
    {
        public static void main(String [] args)
        {    
        
            
            Thread2 th2 = new Thread2();
            Thread th = new Thread(th2);
            th.start();
            new Thread(th2).start();
            new Thread(th2).start();
            // 此处多个线程共享资源ticket
            
        }
    }

    7. 多线程的安全问题:

    当多个语句操作同一个线程共享数据,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来,导致共享数据错误。 

    java对多线程安全问题提供了专业的解决方式:  同步代码块

    synchronized(对象){  需要被同步的代码  }

    对象如同锁,持有锁的线程可以在同步中执行,没有锁的线程即使有CPU执行权,也进不去。

    同步的前提:   有2个以上的线程;  必须多个线程使用同一个锁;  

    好处:解决了多线程的安全问题

    弊端:多个线程需要判断锁,较消耗资源

    8.同步的另一种方式: 同步函数  

    同步函数用的是哪一个锁呢?

    函数因为需要被对象调用,那么函数都有一个所属对象引用,就是this,同步函数使用的锁是this

    静态同步函数使用的锁是该函数所在类的字节码文件对象  类名.class

    class Ticket implements Runnable
    {
        private static  int ticket = 30;    
        public void run()
        {    
            while(ticket>0)
            {    
                    if(ticket>0)
                    {                
                        show();
                    }
            }
            
        }
        
        static synchronized void show()  //Ticket.class
        {
            try { Thread.sleep(10); }
            catch(Exception e){}
            System.out.println(Thread.currentThread().getName()+"tickete="+ticket--);
        
        }
        
    }

    9.单例设计模式

    //懒汉式: 单例设计模式,特点:实例延迟加载
    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;
        }
    }
    //饿汉式
    class Single
    {
        private static final Single s = new Single();
        private Single() {}
        public  static Single getInstance()
        {
            return s;
        }
    }

    10. 死锁示例:

    class Test implements Runnable
    {
        public static boolean flag = true;
        
        public void  run()
        {
            if(flag)
            {    
                while(true)
                {
                    synchronized(this)
                    {   
                        System.out.println("线程1-1");
                        synchronized(Test.class)
                        {
                            System.out.println("线程1-2");
                        }
                    }
                }
            }
            else
            {
                while(true)
                {
                    synchronized(Test.class)
                    {   
                        System.out.println("线程2-1");
                        synchronized(this)
                        {
                            System.out.println("线程2-2");
                        }
                    }
                }
            }
            
        }
    }
    
    class Main
    {
        public static void main(String [] args)
        {
            Test t = new Test();
                
            new Thread(t).start();
            try { Thread.sleep(5); }  catch(Exception e){}
            t.flag = false;
            new Thread(t).start();
            
        }
    }

    11. 同步唤醒机制:

     wait( )    notify()   notifyAll()  

    都使用在同步中,因为要对持有锁的线程操作。  只有同步才具有锁。

    wait()会使锁中的线程释放锁。醒来之后,当再次分配到锁时,从刚才的位置继续执行

    为什么这些操作线程的方法要定义在 Object 类中?

    因为这些方法在操作线程时,都必须要标识他们所操作线程 持有的锁。

    只有同一个锁上的被等待线程,可以被同一个锁上的 notify 唤醒, 不可以被不同锁中的notify唤醒。

    而锁可以是任意对象,所以可以被任意对象调用的方法定义在 Object 类中。

    12. 生产者消费者模式:

    对于多个生产者和消费者,为什么定义while 判断标记?    让被唤醒的线程再一次判断标记

    为什么定义 notifyAll()   因为用notify可能出现唤醒本方线程的情况,导致程序中所有线程都等待。

    JDK1.5中提供了多线程升级解决方案。(显式的锁机制)

    将同步 synchronized 替换成现实 Lock 操作,

    将 Object 中的wait notify notifyAll 替换成了 Condition 对象,该对象可以由Lock锁获取。

    13. 停止线程、 守护线程

    停止线程:  stop()方法已过时

    一种方法是在 run()方法中结束。 多线程的运行代码通常是循环结构,只要控制住循环,就可以让run 方法结束,也就是线程结束。

    特殊情况,当线程处于冻结状态,读取不了标记,run方法无法结束进程,需要  Thread. interrupt()方法:  

    当调用了Object类的 wait 方法或者Thread 类的join 、 sleep 方法时,线程阻塞,

    interrupt 方法将处于冻结状态的线程强制恢复到运行状态。

    setDaemon(boolean on)   守护线程必须在启动线程前启用;  当前台线程都停止时,守护线程自动退出,JVM退出。

    14. join 方法

    当A线程的代码执行到了 B线程的 .join() 方法时,A就会等待,等B线程都执行完,A才会执行。

    join可以用来临时加入线程执行。

    15. toString() 
              返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

    线程默认优先级是 5 ,最小是1,最大是10。

    class Main
    {
        public static void main(String [] args)
        {    
            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
            System.out.println(Thread.currentThread().toString());    
        }
    }

    优先级为10时,抢到执行权的频率高一些而已,其他线程也有机会抢到。

    Thread.yield()  线程执行到yield方法时,暂停正在执行的线程,执行其他线程。

    yield方法造成多个线程交替执行,相对避免了一个线程连续多次抢到执行权

    16.  某些代码需要被同时执行时,就需要用单独的线程进行封装。

  • 相关阅读:
    阅读ARm芯片手册 阅读方法
    Linux驱动mmap内存映射
    Linux下inotify的基本使用及注意事项
    网络视频监控与人脸识别
    Linux pci驱动源码
    Verilog语法
    跟着我从零开始入门FPGA(一周入门XXOO系列)-1、Verilog语法
    周立功-我的25年嵌入式生涯
    Linux 进程学习
    [转]MFC下关于“建立空文档失败”问题的分析
  • 原文地址:https://www.cnblogs.com/tyh2014/p/4240559.html
Copyright © 2020-2023  润新知