zoukankan      html  css  js  c++  java
  • java-多线程操作全(Thread)-Timer简单使用

     一、 多线程概念和作用

     线程指进程中的一个执行场景,也就是执行流程,那么进程和线程的区别是什么

      1.每个进程是一个应用程序,都有独立的内存空间

      2.同一个进程中的线程共享其进程中的内存和资源

      (共享的内存是堆内存和方法内存,栈内存不共享,每个线程有自己的堆内存)

     进程:进程对应一个应用程序

      现在的计算机都是支持多进程的,在同一个操作系统中,可以同时启动多个进程 

      

     多进程的作用:

     * 单进程只能做一件事 : 一边玩游戏,一边听音乐不是同时运行,而是进程之间的频繁调度,切换速度极高,感觉是同时进行。

     * 多线程的作用不是提高执行速度,而是提高CPU的使用率。进程和进程之间的内存是独立的、

     * 线程:是进程中的执行场景。一个进程可以启动多个线程。

     * 多线程的作用:不是为了提高执行速度,而是为了提高应用程序的使用率

     

     * java程序的运行原理

     * java命令启动java虚拟机,启动JVM,等于启动一个应用程序,表明启动一个进程。该进程会自动启动一个“主线程”,然后主线程去调用某各类的main方法。

     * 所以,main方法运行在主线程中。在此之前的所有程序都是单线程的。

     

     二、线程的创建和启动

     

     *Java虚拟机的主线程入口是main方法,用户可以自己创建线程,创建方式有两种

     *1.继承Thread类

     *2.实现Runnable接口(推荐使用Runnable)

     

     *继承Thread类

     *采用 Thread类创建线程,用户只需要继承 Thread,覆盖 Thread中的run方法,父类 Thread中的run方法没有抛出异常,那么子类也不角能抛出异常,最后采用start启动线程即可

     

     实现Runnable接口

     Thread对象本身就实现了 Runnable接口,但一般建议直接使用 Runnable接口来写多线程程序,因为接口会比类带来更多的好处

     

    三、java语言中实现多线程第一种方式

     

    1.继承java.lang.Thread

    2.重写run方法

    三个知识点 :定义线程 、创建线程、 启动线程

    package com.steven.demo;
    
    import java.lang.Thread;
    public class ThreadTest {
      public static void main(String[] args) {
    
        Thread thread = new Student();
        //启动线程
        thread.start();//打印Run:0~9
        //start方法执行完瞬间结束,告诉JVM再分配一个新的线程 给t线程
        //是随机分配的,没有规律
        
        //run不需要手动调用,系统程序启动之后会自动调用方法
        //thread.run();//这是普通方法的调用,这样做程序只有一个线程,run方法结束之后,下边的程序才会执行
        
        for (int i = 0; i < 5; i++) {
            System.out.println("main"+i);
        }
        //有了多线程之后,main方法结束只是主线程中没有方法栈帧了 但是其他线程或者其他栈中还有栈帧  main方法结束,程序可能还在运行
      }
    }
    
    class Student extends Thread {
        //重写Run方法
        public void run() {
           for (int i = 0; i < 10; i++) {
            System.out.println("Run:"+i);
           }
        }
    }

    四、java语言中实现多线程第二种方式

    1.写一个类实现

    2.重写run方法

     

    package com.steven.demo;
    
    import java.lang.Runnable;
    import java.lang.Thread;
    public class ThreadTest02 {
       public static void main(String[] args) {
        //创建线程:
        Thread thread = new Thread(new Teacher());
        //启动线程
        thread.start();
       }
    }
    class Teacher implements Runnable {
        //重写Run方法
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("Run:"+i);
            }
        }
    }

    五、掌握线程方法

    1.获取当前线程的对象 Thread.currentThread()

    2.给线程起名t.setName()

    3.获取线程的名字:t.getName()

     

    package com.steven.demo;
    public class ThreadTest03 {
      public static void main(String[] args) {
        
          //获取当前线程的对象 main主线程
          Thread thread = Thread.currentThread();
          //获取当前线程的名字
          System.out.println("当前名称的名称"+thread.getName());//当前名称的名称main
          
          Thread t1 = new Thread(new ArrayTest());
          //给线程起名
          t1.setName("Steven");
          t1.start();//线程的名称Steven
          
          Thread thread2 = new Thread(new ArrayTest());
          //给线程重命名
          thread2.setName("珂珂");
          thread2.start();//线程的名称珂珂
      }
    }
    class ArrayTest implements Runnable {
        public void run() {
            Thread thread = Thread.currentThread();//获取当前线程的对象
            System.out.println("线程的名称"+thread.getName());
        }
    }

    六、线程的优先级

    优先级高的获取CPU时间片,相对多一些

    最高:10

    最小:1

    默认:5

    优先级1-10

    优先级高的线程,会得到CPU的时间多一些,优先执行完成

     

    public class ThreadTest04 {
      public static void main(String[] args) {
        System.out.println("最高"+Thread.MAX_PRIORITY);
        System.out.println("最小"+Thread.MIN_PRIORITY);
        System.out.println("默认"+Thread.NORM_PRIORITY);
        
        Thread t1 = new Thread(new KeKe());
        t1.setName("t1");
        
        Thread t2 = new Thread(new KeKe());
        t2.setName("t2");
        
        //获取线程的优先级
        System.out.println("t1优先级"+t1.getPriority());
        System.out.println("t2优先级"+t2.getPriority());
        
        //设置优先级
        t1.setPriority(5);
        t2.setPriority(6);
        
        //启动
        t1.start();
        t2.start();//线程虽然有优先级,但是随机分配的,打印结果不一致
      }
    }
    class KeKe extends Thread {
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"----------------"+i);
            }
        }
    }

    七、线程休眠

    ①Thread.sleep()使当前正在执行的线程执行休眠操作(暂停执行) 单位:毫秒

    sleep 静态方法 作用: 阻塞当前线程,腾出CPU,让给其他线程

    public class ThreadTest05 {
    
        public static void main(String[] args) {
            Thread thread = new Array1();
            thread.setName("thread1");
            thread.start();
            //获取当前线程的对象 main主线程
              Thread t = Thread.currentThread();
              //获取当前线程的名字
              System.out.println("当前名称的名称"+t.getName());//当前名称的名称main    
              
              //阻塞主线程
              for (int i = 0; i < 10; i++) {
                  System.out.println(Thread.currentThread().getName() + "-------------------:" + i);
                    try {
                        Thread.sleep(2000);//程序休眠2秒钟
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
            }
        }
    }
    class Array1 extends Thread {
    
        public void run() {
            System.out.println("线程正在启动=-====");
            for (int i = 0 ; i < 5 ; i ++) {
                System.out.println(Thread.currentThread().getName() + "-------------------:" + i);
                try {
                    Thread.sleep(2000);//程序休眠2秒钟
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    ②Thread.yield()暂停当前正在执行的线程对象,并执行其他线程。

     1.静态方法

     2.作用:给同一个优先级的线程让位,但是让位时间不固定

     3.和sleep方法相同,就是yield的时间不固定

     他与sleep类似,只是不能由用户执行暂停时间,并且yield()只能让同优先级的线程有执行的机会

     

    package com.steven.demo;
    public class ThreadTest07 {
      public static void main(String[] args) {
          //1.创建线程
           Thread thread = new HThread();
           thread.setName("线程07");
           //2.启动线程
           thread.start();
           //3.主线程
           for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() +"---------:"+i);
            }
           System.out.println("Steven=====");
      }
    }
    class HThread extends Thread {
        
        public void run() {
            
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() +"---------:"+i);
                if (i % 2 == 0) {
                    //暂定当前线程,执行其他线程
                    Thread.yield();
                }
            }
        }
    }

    ③线程的基本操作

    /*
     线程的基本操作:创建,启动,休眠,异常处理
     */
    public class ThreadTest06 {
        
       public static void main(String[] args) {
           try {
             //1.创建线程
               Thread thread = new MyThread();
               thread.setName("线程");
               //2.启动线程
               thread.start();
               //3.休眠
               Thread.sleep(2000);
               System.out.println("Steven=====");
           }catch (InterruptedException e) {
               e.printStackTrace();
           }   
       }
    }
    
    class MyThread extends Thread {
        
        public void run() {
            for (int i = 0; i < 10; i++) {
                
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                
                System.out.println(Thread.currentThread().getName() +"---------:"+i);
            }
        }
    }

    八、线程的合并(join)

    public class ThreadTest08 {
       public static void main(String[] args) {
         
       try {
         //1.创建线程
           Thread thread = new KThread();
           thread.setName("线程07");
           //2.启动线程
           thread.start();
           //3.合并线程 (线程07和main线程合并)
           thread.join();//输出只保证一个线程正在执行,依次执行,单线程的程序 (先执行线程07后执行main)
          //主线程
           for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() +"---------:"+i);
            } 
           //当前线程可以调用第一个线程的join方法,调用后当前线程会被阻塞不再执行,直到被调用的线程执行完毕,当前线程才会执行
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       }
    }
    class KThread extends Thread {
        
        public void run() {
            
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(2000);
                    System.out.println(Thread.currentThread().getName() +"---------:"+i);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                };
                
            }
        }
    }

    九、线程同步案例

    <1>模拟取款:(不使用同步机制)多线程同时对同一个账号进行取款操作

     

    /*
    模拟取款:不使用同步机制,多线程同时对同一个账号进行取款操作
    thread 和 thread2
    异步编程模型:thread线程执行的是thread , thread2线程执行的是thread2 ,两个线程之间谁也不等于谁
    同步编程模型:thread线程和thread2线程执行,当thread线程必须等thread2的线程的执行结果之后,thread线程才能执行 ,这是同步编程
    
    什么时候需要引入同步:
    1.为了数据安全,尽管程序的使用率低,但是为了保证数据安全性,必须得加入线程同步机制, 线程同步机制 使程序变成了单线程(一个线程)
    2.在什么条件下需要使用线程同步
    <1>必须是多线程环境
    <2>多线程环境在共享同一个数据时
    <3>共享的数据涉及到修改操作
     */
    package com.steven.demo;
    
    public class ThreadTest09 {
       public static void main(String[] args) {
         //创建一个公共的账户
        Account account = new Account("steven_kou",10000.0);
        
        //创建线程对同一个账户进行取款
        Thread thread = new Thread(new Money(account));
        thread.setName("steven");
        Thread thread2 = new Thread(new Money(account));
        thread2.setName("kou");
        
        thread.start();
        thread2.start();
       }
    }
    
    //取款线程
    class Money implements Runnable {
    
        //账户
        Account account;
        
        Money (Account account){
            this.account = account;
        }
        
        public void run() {
            account.withDraw(2000.0);
            System.out.println("取款2000.0$,余额为:"+account.getBalance());//取款2000.0$,余额为:8000.0 (输出两次)
        }
        
    }
    
    //银行账户
    class Account {
        
        private String actno;
        private double balance;//账户余额
        
        public Account() {}
        public Account(String actno,double balance) {
            this.actno = actno;//成员变量|局部变量
            this.balance = balance;
        }
        
        public void setActno(String actno) {
            this.actno = actno;
        }
        
        public String getActno() {
            return actno;
        }
        
        public void setBalance(double balance) {
            this.balance = balance;
        }
        
        public double getBalance() {
            return balance;
        }
        
        //对外提供一个取款方法
        public void withDraw(double money) {
            //对账户进行取款操作
            double after = balance - money;
            //延迟操作
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();//InterruptedException 线程中断下抛出的异常
            }
            this.setBalance(after);//更新账户余额,重新赋值
        }
    }

    <2>模拟取款(同步机制,同步锁synchronized

    ①以下程序使用线程同步机制保证数据安全

     

    package com.steven.demo;
    public class ThreadTest09 {
       public static void main(String[] args) {
         //创建一个公共的账户
        Account account = new Account("steven_kou",10000.0);
        
        //创建线程对同一个账户进行取款
        Thread thread = new Thread(new Money(account));
        thread.setName("steven");
        Thread thread2 = new Thread(new Money(account));
        thread2.setName("kou");
        
        thread.start();
        thread2.start();
       }
    }
    
    //取款线程
    class Money implements Runnable {
    
        //账户
        Account account;
        
        Money (Account account){
            this.account = account;
        }
        
        public void run() {
            account.withDraw(2000.0);
            System.out.println("取款2000.0$,余额为:"+account.getBalance());//取款2000.0$,余额为:8000.0 (输出两次)
        }
        
    }
    
    //银行账户
    class Account {
        
        private String actno;
        private double balance;//账户余额
        
        public Account() {}
        public Account(String actno,double balance) {
            this.actno = actno;//成员变量|局部变量
            this.balance = balance;
        }
        
        public void setActno(String actno) {
            this.actno = actno;
        }
        
        public String getActno() {
            return actno;
        }
        
        public void setBalance(double balance) {
            this.balance = balance;
        }
        
        public double getBalance() {
            return balance;
        }
        
        //对外提供一个取款方法
            //TODO 取款 同步
            public void withDraw(double money) {
                /*
                 需要把同步的代码,放到同步的语句块中
                 thread线程执行到此处,遇到了synchronized 关键字,就会去找this的对象锁 如果找到了this的对象锁,则进入同步语句块 执行程序
                 当同步语句块代码执行结束的时候,thread线程归还this的对象锁
                 
                  在thread线程执行同步语句块的过程中,如果thread2线程也执行以下代码。遇到synchronized 关键字,所以去找this对象锁,但是该对象被thread线程持有, 只能等待thread线程使用完以后再解锁this对象锁
                 */
                
                //同步锁
                synchronized (this) {
                    //对账户进行取款操作
                    double after = balance - money;
                    //延迟操作
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();//InterruptedException 线程中断下抛出的异常
                    }
                    //更新账户余额,重新赋值
                    this.setBalance(after);
                }
            }
    }

    ②synchronized关键字 添加到成员方法上,线程拿走的也是this对象锁

    //对外提供一个取款方法
        //TODO 取款 同步
        //synchronized关键字 添加到成员方法上,线程拿走的也是this对象锁
        public synchronized void withDraw(double money) {
            /*
             需要把同步的代码,放到同步的语句块中
             thread线程执行到此处,遇到了synchronized 关键字,就会去找this的对象锁 如果找到了this的对象锁,则进入同步语句块 执行程序
             当同步语句块代码执行结束的时候,thread线程归还this的对象锁
             
             在thread线程执行同步语句块的过程中,如果thread2线程也执行以下代码。遇到synchronized 关键字,所以去找this对象锁,但是该对象被thread线程持有, 只能等待thread线程使用完以后再解锁this对象锁
             */
            
            //同步锁
    //            synchronized (this) {
                //对账户进行取款操作
                double after = balance - money;
                //延迟操作
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();//InterruptedException 线程中断下抛出的异常
                }
                //更新账户余额,重新赋值
                this.setBalance(after);
    //            }
        }

    三、守护线程

    ①定义一个用户线程

    package com.steven.demo;
    
    //定义一个用户线程
    public class UserThread01 {
       public static void main(String[] args) {
         Runnable runnable = new UserTest();
         Thread thread = new Thread(runnable, "UserThread");
         thread.start();
         for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "==== " + i);
            }
         System.out.println("主线程结束---");
      }
    }
    
    class UserTest implements Runnable {
        
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "==== " + i);
            }
            
        }
    }

    ②改为守护线程

    package com.steven.demo;
    //守护线程
    //其他所有的用户线程结束,则守护线程退出
    //守护线程一般都是无限执行的 守护线程最后结束(先执行用户线程)
    //设置守护线程以后,当前主线程结束后,守护线程并没有把所有的数据输出就结束 也就是说 守护线程是为用户线程服务的,当用户线程全部结束,守护线程会自动化结束
    
    public class UserThread02 {
        public static void main(String[] args) {
            Thread thread = new UserTest02();
            thread.setName("thread");
            //将thread这个用户线程 修改为守护线程
            thread.setDaemon(true);
            thread.start();
            //主线程 
             for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "==== " + i);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
             System.out.println("主线程结束---");
        }
    }
    class UserTest02 extends Thread {
        public void run() {
            int i = 0;
            while (true) {
                i ++;
                System.out.println(Thread.currentThread().getName() +"====:"+i);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    四、定时器简单使用:

     

    package com.steven.demo;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /*
     Timer 定时器
     */
    public class TimerTest01 {
        
       public static void main(String[] args) {
        System.out.println("来了");   
        Timer timer = new Timer();
        try {
              Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-10-07 19:26:02");
              //安排在指定的时间执行指定的任务
              timer.schedule(new MyTimer(), date,1000*60*60*24);//date执行后续任务的时间间隔   设置定时任务:在2018-10-07 19:26:02执行此任务, 24小时执行一次
              //timer.schedule(new MyTimer(), date,1000*2);
              //如果设置每天执行一次:Date date = new SimpleDateFormat("HH:mm:ss").parse("19:26:02");
              
        }catch (ParseException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
          
       }
    }
    
    class MyTimer extends TimerTask {
    
        public void run() {
            System.out.println("=="+new Date());//==Sun Oct 07 19:26:02 CST 2018
        }
        
    }

     

     

     

     

     

  • 相关阅读:
    ArrayList removeRange方法分析
    LinkedHashMap源码分析(基于JDK1.6)
    LinkedList原码分析(基于JDK1.6)
    TreeMap源码分析——深入分析(基于JDK1.6)
    51NOD 2072 装箱问题 背包问题 01 背包 DP 动态规划
    51 NOD 1049 最大子段和 动态规划 模板 板子 DP
    51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子
    8月20日 训练日记
    CodeForces
    CodeForces
  • 原文地址:https://www.cnblogs.com/StevenHuSir/p/Java_Thread.html
Copyright © 2011-2022 走看看