zoukankan      html  css  js  c++  java
  • Thread线程的方法用法,有代码例子,简单易懂


    /**
     *  程序 :
     *      就是指我们写的保存硬盘当中的静态文件,叫程序
     *  进程 :  
     *      就是程序被加载进内存,准备或者正在运行时,就叫进程
     *  线程 :
     *      就是程序中不同的执行路径
     *
     *  线程 :
     *      当我们程序开始执行的时候,就是java中main()方法开始执行,在栈内存中开辟main()栈帧的时候,就是开启了一个线程
     *      一个线程就是一个栈及其里面的链式栈帧,一个栈帧就对应一个方法.
     *  
     */
    ☆☆☆☆ 重点 ☆☆☆☆ !
        创建一个新的线程有两种方式,
        但是启动一个线程,只有一种方式(唯一的一种);
        //三个要点 :
                线程的定义;
                线程的启动;
                线程开启之后;
           // 线程的定义 :
                    程序不同的执行路径,从代码角度来讲,线程就是一个类,从内存角度来讲,线程就是一个栈和链式栈帧
           // 线程必须要先启动 :
               start();//成员方法
           // 一旦开启多线程 :
                    这个时候,说代码是从左到右,从上往下执行这句话就不准确了,因为,我们开启了两个线程,在每个线程的内部,仍然是从上到下,从左到右,但是线程之间的代码,没有固定的先后顺序,他们执行的先后顺序,是不确定的,和CPU,操作系统,和我们自己的设定,都相关

    Thread :    
        //创建线程
        创建一个新的线程,有两个方式 :
            //第一种 :
                    第1步 : 继承java.lang.Thread;这个类
                    第2步 : 重写run()方法,为什么要重写?因为run()就相当于新线程的main()方法,就是程序执行的起点和终点;

                //创建了线程,不启动,不能用 : start();
            //开启线程 :
                Thread t = new 子类名();
                t.start();//就开启线程了
    Runnable :

            //第二种 :
                    第1步 : 实现java.lang.Reunnable接口
                    第2步 : 实现接口的run()方法;
            //开启线程 :
                1 Thread t = new Thread(new 子类名());
                   t.start();//开启线程
                2 Runnable(或者是子类名) r = new 子类名();//多态
                  Thread t = new Thread(r);
                  t.start();//开启线程

    Thread_start :
            start();//启动线程(唯一的方法) 默认会去调用该线程的run()方法 成员方法
            启动一个线程 : 只能是Thread类中的start()方法;

    currentThread :
            
            currentThread();//获取当前线程的内存地址 静态方法,类名调用就行 对象名也行,底层会默认转换为类名
            Thread.currentThread();//获取当前线程的内存地址(在哪个线程写的,Thread就是哪个线程)

    setName :
        
            setName();//给线程取名字,不设置默认是Thread-0,依次累加
            Thread t1 = new 子类名();//默认的名字是在new的时候取得 Thread-0
            t1.setName("t1");//现在,线程名字就改为t1了
            t1.start();
            
    getName :
            
            getName();//获得当前线程的名字  成员方法
            Thread.currentThread().getName();//因为getName()是成员方法,所以想调用这个方法,要先获得当前线程的内存地址吧,就是Thread.currentThread();

    sleep :
        
        sleep : 在那个线程写的,就锁定那个线程,和 用哪个线程的引用调用sleep()没有关系(因为底层也会默认转成类名)
        //让某个线程休眠 可以直接类名调用就行了
        //线程中,加了sleep(),就必须抛异常或者捕捉异常
        sleep();//让当前线程睡眠指定的毫秒数  是静态方法 类名调用就行
        Thread.sleep(1000);//让该线程睡眠 1 秒;写在那个线程,就睡眠那个线程

    setPriority :
        
        setPriority();//设置线程的优先级  成员方法
        线程的默认优先级 :
            //子线程默认继承父类的线程优先级
            java中线程的优先级有0-10 11个级别
            win当中是1-7 7个优先级
            MIN_PRIORITY : 1  //最低
            MAX_PRIORITY : 10 //最大
            NORM_PRIORITY : 5 //正常

            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);//(设置当前线程的优先级)成员方法要用对象引用去调用吧.先获取当前线程的内存地址,调用setPriority();去设置优先级 这里设置的为 1 最低的  不设置默认为 5 NORM_PRIORITY
            Thread t = new 子类名();
            t.setPriority(Thread.MAX_PRIORITY);//这和上面那个是一样的,只不过上面那个,写在哪,就设置那个线程的优先级,这个是设置指定的那个线程的优先级

    //唤醒休眠的两种方法 :
        
        1 Interrup();//异常唤醒,需要捕捉和抛异常
        2 while();//循环

            Interrup :
                Interrup();//这种方式唤醒,一定要try...catch..处理异常或者是throws抛异常  
                //异常类型 : InterruptedException

                Thread t = new 子类名();//这种是继承Thread并覆写run()方法的,这种创建线程方式
                Thread t = new Thread(new 子类名());//这种是实现Runnable接口,并实现run()方法的,这种创建线程方式
                t.start();//启动线程
                t.interrupt();//强行唤醒(异常唤醒)

            while :
               用while循环(或者别的循环,加if),
               需要强行唤醒,就在主线线程设置 引用(对象名).run=false;就行了
               boolean run = true;//成员变量
               int i =0;//成员变量
               public void run(){//线程类的run()方法
                   while(run){//循环 这里如果为true 就会一直循环(死循环把)
                       i++;
            MIN_PRIORITY : 1
                       try{
                           Thread.sleep(1000);
                       }catch(Exception e){
                           e.printStackTrace();
                       }
                       System.out.println( Thread.currentThread().getName()+"--->"+i );
                   }
               }

    join :
        
        join();//也就是线程的合并,把两个线程,合并成一个线程(成了单线程)  成员方法
        等着当前线程执行完毕,然后再在本线程后面继续往下执行,当前行以后,所有的main线程的代码,都必须等着这个线程执行完毕以后再执行,相当于这个线程和main线程合并,变为单线程程序,又是从上往下执行
            Thread t = new 子类名();
            t.start();//启动线程
            t.join();//这行一下的main线程的代码,都必须等待t执行完,才能继续执行

    yield :
        
        yield();//静态方法 可以直接类名调用,让当前线程让位一次(只跟同级)
                1 这是一个静态方法,一维这:即使用对象调用他,也会在底层转换为类名调用,停掉的也还是当前所在的线程,也就是说在那个类中调用,就停止那个线程
                2 给同一个优先级的线程让位,不同的优先级,不让位
                3 和sleep()方法相同,那个线程调用就停止那和累的线程,但是没有时间,不固定,只是让出当前这个时间片,下一个时间片让不让,另说

                Thread.yield();//跟同级线程,让位一次 写在哪,哪个就让位一次
            
    synchronized: :
        
            synchronized : 并不是往对象里面加锁,锁是每个对象都有的属性,synchronized只是锁上了这把锁,是个持续的动作而已
            synchronized 是一个修饰符,修饰的方法,等于是给方法加了一把钥匙,当一个线程执行这个方法的时候,别的所有线程都不能再去执行这个方法,和用synchronized修饰的方法,一个方法锁住,所有用synchronized修饰的方法都会锁上,但是没有用synchronized修饰的方法,可以访问//目的就是让数据同步
            //线程同步本质 :
           当多个线程(服务,任务),操作同一个数据的时候,保证数据一致,本质就是数据同步,是一种数据安全机制
           这种机制,操作上更多是从数据上来保护的
       //异步编程模型 :
           线程是完全独立的,谁的运行也不会受到别的线程的影响
       //同步编程模型 :
           线程间不是独立的,互相间有影响的,某些线程必须单独完成任务以后,才能 够让别的线程执行(为什么?)
           
           //同步的原因 :
               1 同步是指数据的同步,为了数据安全,必须要等某个线程对数据操作完成以后,在引入别的线程进行操作
                   同步机制,某种程度是多线程编程变成了单线程
               2 同步的环境
                   1 必须多线程
                   2 多个线程有同时操作同一个数据的可能性
                   3 主要就是涉及数据更改的操作
           线程同步是数据的概念
           //方法 : 锁定,锁定是一个逻辑上的概念,是为了保证同步的手段
           //方发锁 : 按照封装性,根本不可能再是直接就能对数据进行操作只能通过方法进行操作
           //对象锁 : 堆内存,只要一加锁,谁也进不来
           //类锁 : 更大级别的
           只要加了 synchronized 修饰的成员方法(静态方法),是多个线程不可以用加了synchronized的方法同时访问这个对象(类)
       同一个方法互斥,不同的方法也互斥

        //静态方法声明 :
                又称为类锁;
                public synchronized static void m1(){
                 System.out.println( "不管谁被锁,我都会被锁,他解开,我才解开" );   
                }
                public synchronized static void m2(){
                    System.out.println( "不管谁被锁,我都会被锁,它解开,我才解开" );
                }
                public static void m3(){
                    System.out.println( "别人锁不锁,干我何事" );
                }
            比如我有两个线程,t1和t2把
                t1调用了m1();/*就会锁住*/ t2就不能调用m1()和m2();/*m2()也会被锁住*/只能调用m3();//因为m3()没有用synchronized修饰
        
        //成员方法声明 :
                又称对象锁
                前提是/*对象*/必须是同一个对象
                 public synchronized  void m1(){
                 System.out.println( "不管谁被锁,我都会被锁,他解开,我才解开" );   
                }
                public synchronized  void m2(){
                    System.out.println( "不管谁被锁,我都会被锁,它解开,我才解开" );
                }
                public  void m3(){
                    System.out.println( "别人锁不锁,干我何事" );
                }
                比如我有两个线程,t1和t2把//并且t1线程和t2线程都是同一个对象
                t1调用了m1();/*就会锁住*/ t2就不能调用m1()和m2();/*m2()也会被锁住*/只能调用m3();//因为m3()没有用synchronized修饰

    setDaemon :
        
            setDaemon();//设置守护线程(兜底线程)
            只要主线程执行完毕,不管守护线程执行了多少,执行到哪,都不会在执行,也跟着死去,但是跟主线程晚结束一下,
                //活,他先活,死,他先死(要么怎么守护,守护线程,先活,后死)
            Thread t1 = new 子类名();//创建一个线程把,用的是继承的方式
            t1.setDaemon(true);//里面是布尔型 true/false  把当前线程设置为守护线程
            t1.start();//启动t1线程把
            //如果我守护线程里面有个死循环(就是不会结束的那种),但是,只要主线程执行完毕,守护线程也会跟着结束

    Timer :
        
            1 创建一个定时器(Timer)
            2 创建一个执行定时器任务的类,这个类必须继承于 TimerTask 这个类,并且,必须覆写 TimerTask 类中的 run(),方法.(TimerTask)
            3 用 Timer 类里面的 schedule()方法,分配并执行定时器任务(schedule)
        Timer :
            Timer t = new Timer();//创建一个定时器,并且调用Timer类里面的 schedule()方法,分配执行的任务
        
        TimerTask :
            class 类名 extends TimerTask{
                public void run(){
                     System.out.println( new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) );//获取当前时间,输出
                }
            }
            Date :
                Date d = new Date();//获取当前的时间
                String d1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(d);//以这种形式,输出当前时间d

    schedule :

        schedule();//Timer里面的schedule(要执行任务的类对象 , 起始的时间 , 任务执行间隔的毫秒数 );//循环执行方法,默认调用run()方法
            t.schedule(
                    new 类名(),/*执行定时器任务的类的对象*/
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2015-09-10 14:48:00 000"),/*其实时间(从什么时间,开始执行)*/
                    1000*3)/*执行任务的间隔时间*/;


    synchronized :
            //死锁
            synchronized : 并不是往对象里面加锁,锁是每个对象都有的属性,synchronized只是锁上了这把锁,是个持续的动作而已
            死锁 : 死锁就是大家都访问不了的状态;
                原理 :
                    1 两个线程,两个对象
                    2 先后 嵌套 锁定 执行 两个对象(先锁定第一个对象,再嵌套锁定第二个对象)
                    3 先后 嵌套 锁定 执行 两个对象(先锁定第二个对象,再嵌套锁定第一个对象)
                    4 在第一个线程执行过程中,执行到第二个对象的时候,发现第二个被锁死了,也只能等待
                    5 第二个线程执行过程中,执行到第一个对象的时候,发现第一个被锁死了,也只能等待

        public class Thread线程{
            public static void main(String[] args){

            //这里我用Object是因为不用再写实体类了,这个类可以自己写
            Object o1 = new Object();//第一个对象
            Object o2 = new Object();//第二个对象

            Thread t1 = new Thread(new T1(o1,o2));//第一个线程(调用的是有参构造把)
            Thread t2 = new Thread(new T2(o1,o2));//第二个线程
            t1.start();//启动线程
            t2.start();//启动线程

        }
    }


    class T1 implements Runnable{//线程类吧
        Object o1;//成员变量 这里用于接收实参传进来的Object的对象引用(实体类用的那个类,这里就要用那个类去接吧)
        Object o2;
        T1(Object o1,Object o2){//有参构造
            this.o1 = o1;//赋值
            this.o2 = o2;
        }
        public void run(){//覆写的run()方法
            synchronized(o1){//锁定第一个对象 (o1)
                try{
                    Thread.sleep(1000);//不睡眠一秒,有时候不死锁,睡眠一秒,百分百死锁(因为如果是我t1线程执行完了,t2线程在开始执行的呢?那就不是死锁了吧,这样,t1到这停一秒,一秒足够t2也走的o2的那个对象那里,所以就死锁了,都在等待)
                }catch(Exception e){
                    e.printStackTrace();
                }
                synchronized(o2){//在锁定第一个对象(o1)中 嵌套锁定第二个对象(o2)
                    System.out.println( "t1" );//如果,t1执行完成了,就会输出 但是如果死锁了,t1就进不来吧 就不会输出
                }
            }
        }
    }
    class T2 implements Runnable{//创建线程类
        Object o1;//成员变量 这里用于接收实参传进来的Object的对象引用(实体类用的那个类,这里就要用那个类去接吧)
        Object o2;
        T2(Object o1, Object o2){//和上面一样,不懂就看上面的注释
            this.o1 = o1;
            this.o2 = o2;
    }
            public void run(){
                synchronized(o2){//t1线程先锁定的o1,我这里如果先锁定o2,没有关系吧,t1能进o1,但是我也能进o2 ,因为是不同的对象,但是我如果再想进o1,是不是就进不去了(因为t1进去就锁了)
                try{
                    Thread.sleep(1000);//这个也停一秒,就是当t2进来o2这个对象,并锁定了,t1也肯定就能进去o1这个对象,并也锁定了,现在就开始进入等待了吧,就是死锁
                }catch(Exception e){
                    e.printStackTrace();
                }
                synchronized(o1){//嵌套锁定o1
                    System.out.println( "t2" );
                }
            }
       }
    }

    wait :

        wait是 Object 类的方法 ,不是Thread中的方法 Thread中wait也是继承于 Object

        注意 : 如果该对象没有被锁定,则调用wait方法,就会报错,即只有在同步方法或者同步代码块中(也就是某线程访问,用 synchronized 修饰的方法之后)才可以调用wait方法,notify,notifyAll同理

        this.wait();不是让当前对象wait,而是让当前锁定this对象的线程wait,同时 释放对this的锁定

        //wait()和sleep()的区别 :

                wait : wait()会把锁打开,让别的线程进来,并且自身进入睡眠,只能等待唤醒,如果不唤醒,会一直休眠(并且,当前线程wait()下面的代码不会执行,只能等待唤醒,才能执行)

                sleep : sleep()就算设置了休眠,但是锁也不会打开,别的线程也进不来,并且可以唤醒,但是如果不唤醒,到了指定的睡眠时间,自身也会唤醒(并且,当前线程sleep()下面的代码不会执行,只能等待唤醒,才能执行)

            this.wait();//如果这个休眠,会打开锁,让别的线程执行
            System.out.println( "我在睡眠" );//不会执行,如果没有线程唤醒,永远不会执行,会永远睡眠

            Thread.sleep(5000);//睡眠5秒,并且不会打开锁,别的线程也得等着,一样进不来
            System.out.println( "我快唤醒了" );//如果没有线程唤醒当前睡眠的线程,那么,5秒后,自动醒,一样会输出


    notify :

            notify是Object 类的方法 ,不是Thread中的方法 Thread中notify也是继承自Object

            注意 : 如果该对象没有被锁定,则调用wait方法,就会报错,即只有在同步方法或者同步代码块中(也就是某线程访问,用 synchronized 修饰的方法之后)才可以调用wait方法,notify,notifyAll同理

            notify() : 随机唤醒一个在该对象上睡眠的某一个线程(一般都是谁先睡眠,谁先醒,具体不知道,是系统随机唤醒的),并且,没有让自身进入睡眠状态
                this.notify();//随机唤醒一个在该对象上睡眠的线程
                System.out.println( "我能输出" );//我能输出,因为上面只是唤醒了一个线程,并没有让自身进入睡眠状态

    notifyAll :

            notifyAll是Object 类的方法 ,不是Thread中的方法 Thread中notifyAll也是继承自Object

            注意 : 如果该对象没有被锁定,则调用wait方法,就会报错,即只有在同步方法或者同步代码块中(也就是某线程访问,用 synchronized 修饰的方法之后)才可以调用wait方法,notify,notifyAll同理

            notifyAll() : 唤醒在该对象上,所有等待的线程,并且,没有让自身进入睡眠状态
                this.notifyAll();//唤醒所有在该对象上睡眠的线程
                System.out.println( "我能输出" );//我能输出,因为上面只是唤醒了所有线程,并没有让自身进入睡眠状态

  • 相关阅读:
    VMware中Ubuntu 14.04出现Unknown Display问题解决
    VMWare桥接、NAT和only-host三种模式
    Tomcat目录下文件详解
    Java socket2
    Java socket1
    网络基础知识
    java awt 乱码问题
    窗口Dialog
    windowsEvents
    鼠标适配器Adapter
  • 原文地址:https://www.cnblogs.com/xrmqbl/p/4800443.html
Copyright © 2011-2022 走看看