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
        }
        
    }

     

     

     

     

     

  • 相关阅读:
    c#实现MD5加密
    AJAX学习笔记 一:简单的XMLHTTPRequest示例和asp.net异步更新。
    客户端JS验证fileupload控件,设置只允许特定的文件类型。
    三层架构下的用户登录检测。
    常用用户注册页面客户端验证脚本。
    Android Debug Bridge 技术实现原理
    Android反编译与防止反编译
    android用sharepreference保存输入框中的内容
    android include 控件详解
    android程序排序算法实现
  • 原文地址:https://www.cnblogs.com/StevenHuSir/p/Java_Thread.html
Copyright © 2011-2022 走看看