zoukankan      html  css  js  c++  java
  • 多线程的实现及常用方法_DAY23

    1:多线程(理解)

     (1)如果一个应用程序有多条执行路径,则被称为多线程程序。

           进程:正在执行的程序。

           线程:程序的执行路径,执行单元。

           单线程:如果一个应用程序只有一条执行路径,则被称为单线程程序。

           多线程:如果一个应用程序有多条执行路径,则被称为多线程程序。

           举例:迅雷下载,360的管理界面。

           单进程单线程:一个人点一桌菜

           单进程多线程:多个人点一桌菜

           多进程多线程:多个人点多桌菜

        (2)多线程程序实现的两种方案:(掌握 步骤我们一起写,代码你写)

           A:继承Thread类

               a:自定义类MyThread继承Thread类。

               b:重写run方法(),在这里面输出1-100的数据。

               c:创建测试类MyThreadTest,在测试类中创建MyThread类的多个对象。

               d:调用start() ,注意不是run()方法,此外线程开启必须在main方法中代码之前,因为main方法也是一个线程,里面的代码是顺序执行的。

               代码体现:

         public class MyThread extends Thread {
    
    
    
                  public MyThread(){}
    
                  public MyThread(String name) {
    
                      super(name);
    
                  }
    
     
    
                  public void run() {
    
                      for(int x=1; x<=100; x++) {
    
                         System.out.println(getName()+"---"+x);
    
                      }
    
                  }
    
               }
    
     
    
               public class MyThreadTest {
    
                  public static void main(String[] args) {
    
                      MyThread my1 = new MyThread("三国志");
    
                      MyThread my2 = new MyThread("三国杀");
    
     
    
                      //my1.setName("三国志");
    
                      //my2.setName("三国杀");
    
     
    
                      my1.start(); // 注意,调用的是start()方法,而不是run方法
    
                      my2.start();
    
                  }
    
               }
    View Code

           B:实现Runnable接口(更好)

               a:自定义类MyRunnable实现Runnable接口。

               b:重写run方法(),在这里面输出1-100的数据。

               c:创建测试类MyThreadTest,在测试类中创建MyRunnable类的一个对象。

               d:在测试类创建Thread类的多个对象,并把MyRunnable类的一个对象作为构造参数传递。

                 用到的构造器:public Thread(Runnable target,

                                   String name)

               e:调用start()

               代码体现:  

     public class MyRunnable implements Runnable {
    
                  public void run() {
    
                      for(int x=1; x<=100; x++) {
    
                         System.out.println(Thread.currentThread().getName()+"---"+x);
    
                      }
    
                  }
    
               }
    
              
    
               public class MyRunnableTest {
    
                  public static void main(String[] args) {
    
                      MyRunnable my = new MyRunnable();
    
     
    
                      Thread t1 = new Thread(my,"斗地主");
    
                      Thread t2 = new Thread(my,"三国群英传2");
    
     
    
                      t1.start();
    
                      t2.start();
    
                  }
    
               }
    
     
    View Code

     (3)面试题:

            A:如何启动一个线程

           B:start()和run()方法的区别

           C:线程随机性原理

           D:线程的生命周期

           E:线程的安全问题是怎么产生的,以及是如何解决的?

           F:同步解决线程安全问题的方式有几种?

           G:同步代码块的锁对象是谁?同步方法的锁对象是谁?

           F:静态方法的锁对象是谁?

     (4)几个方法

           A、优先级(priority)  

               线程优先级代表了抢占CPU的能力。优先级越高,抢到CPU执行的可能性越大。(一般环境下效果不明显,优先级并非绝对的执行顺序。)

               优先级相关方法:

                public final void setPriority(int?newPriority) 优先级取值:1-10

                public final int getPriority()

    例子:cn.itcast2.demo

    package cn.itcast2;
    /*
     * 线程优先级:
     *         public final int getPriority()获取优先级
     *         public final void setPriority(int newPriority)更改优先级
     */
    public class Demo {
    
        public static void main(String[] args) {
    
            MyThread mt = new MyThread();
            mt.setName("唐嫣");
    //        mt.setPriority(10);
            System.out.println(mt.getPriority());
            
            MyThread mt2 = new MyThread();
            mt2.setName("柳岩");
            mt2.setPriority(1);
            
            mt.start();
            mt2.start();
        }
    
    }
    View Code
    package cn.itcast2;
    
    public class MyThread extends Thread {
    
        @Override
        public void run() {
    
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    View Code

           B、暂停(yield) 

               暂停当前正在执行的线程对象,并执行其他线程。(效果不明显,如果想保证完成线程相互等待一次执行,需要使用到后边的等待唤醒机制 )

               线程礼让相关方法:

               public static void yield()

     例子:cn.itcast2.demo4   cn.itcast2.MyThread1.java

    package cn.itcast2;
    /*
     * 线程礼让:
     *         暂停当前正在执行的线程对象,并执行其他线程
     *         public static void yield()
     */
    public class Demo4 {
    
        public static void main(String[] args) {
            
            MyThread1 myThread = new MyThread1();
            myThread.setName("唐嫣");
            MyThread1 myThread2 = new MyThread1();
            myThread2.setName("高圆圆");
            
            myThread.start();
            myThread2.start();
        }
        
    }
    View Code
    package cn.itcast2;
    
    public class MyThread1 extends Thread {
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+":"+i);
                Thread.yield();
            }
        }
    }
    View Code

           C、加入(join) cn.itcast2.demo3

               等待该线程终止。 即当前线程等待调用join方法的线程执行结束后再执行

               public final void join() throws InterruptedException 

    package cn.itcast2;
    /*
     * 加入线程:
     *         public final void join()
                    throws InterruptedException  等待该线程终止。 即当前线程等待调用join方法的线程执行结束后再执行
     */
    public class Demo3 {
    
        public static void main(String[] args) throws Exception {
            
            MyThread myThread = new MyThread();
            myThread.setName("唐嫣");
            MyThread myThread2 = new MyThread();
            myThread2.setName("高圆圆");
            
            myThread.setPriority(1);
            
            myThread.start();
            
            myThread2.start();
            myThread2.join(); //等待myThread2线程执行完以后,main方法所在的线程才会执行
    
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    
    }
    View Code
    package cn.itcast2;
    
    public class MyThread extends Thread {
    
        @Override
        public void run() {
    
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    View Code

           D、守护线程 

              设置守护线程的方法:

              没有设置为守护线程的线程执行完毕,则程序停止运行

               public final void setDaemon(boolean on)

               注意:该方法必须在线程启动前调用

    例子: cn.itcast2.demo5

    package cn.itcast2;
    /*
     * 守护线程:
     *         设置守护线程的方法:
     *         public final void setDaemon(boolean on)
     *              注意:该方法必须在线程启动前调用
     */
    public class Demo5 {
    
        public static void main(String[] args) {
    
            MyThread1 myThread = new MyThread1();
            myThread.setName("唐嫣");
            MyThread1 myThread2 = new MyThread1();
            myThread2.setName("高圆圆");
            
            myThread.setDaemon(true); //设置守护线程
            myThread2.setDaemon(true);//设置守护线程
            
            myThread.start();
            myThread2.start();
    
            for (int i = 0; i < 10; i++) {  //主线程没有设置为守护线程,主线程执行完毕,则程序停止运行
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    
    }
    View Code
    package cn.itcast2;
    
    public class MyThread1 extends Thread {
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+":"+i);
                Thread.yield();
            }
        }
    }
    View Code

           E、线程睡眠(sleep) 

               指定线程休眠一定时间,进入等待状态。在该段时间结束后,线程重新可执行。

               线程休眠相关方法:

                public static void sleep(long?millis) throws InterruptedException

       例子:cn.itcast2.demo2

    package cn.itcast2;
    /*
     * 线程休眠:
     *     public static void sleep(long millis) throws InterruptedException  将当前线程休眠,指定毫秒值
     */
    public class Demo2 {
    
        public static void main(String[] args) throws Exception {
    
            System.out.println("我困了");
            
            MyThread mt = new MyThread();
            mt.start();
            
            Thread.sleep(3000l);
            System.out.println("我醒了");
            
        }
    
    }
    View Code
    package cn.itcast2;
    
    public class MyThread extends Thread {
    
        @Override
        public void run() {
    
            for (int i = 0; i < 100; i++) {
                System.out.println(getName()+":"+i);
            }
        }
    }
    View Code

           F、线程中断(interrupt) 

               中断线程。

                  stop方法已过时,通常使用interrupt方法。

               中断线程相关方法:

                  public void interrupt()   被中断的线程会报被中断异常,这时需要使用try/catch语句解决相关问题,线程后代码仍然可以继续执行

                  public final void stop()  (已过时)  直接停止线程,线程后代码无法被执行

         例子:cn.itcast2.demo6   cn.itcast2.MyThread2

    package cn.itcast2;
    /*
     * stop方法直接停止线程,方法过于暴力。直接导致sleep后的代码无法执行。
     * 线程中断:
     *              public void interrupt()  抛出异常,处理异常,后边代码继续执行
     */
    public class Demo6 {
    
        public static void main(String[] args) throws Exception {
            
            MyThread2 myThread = new MyThread2();
            MyThread2 myThread2 = new MyThread2();
            
            myThread.start();
            myThread2.start();
            
            Thread.sleep(3000);
            myThread.stop();
            myThread2.interrupt();
        }
    
    }
    View Code
    package cn.itcast2;
    
    public class MyThread2 extends Thread {
    
        @Override
        public void run() {
            
            System.out.println("我困了");
            try {
                Thread.sleep(10000l);
            } catch (InterruptedException e) {
                System.out.println("谁把我叫醒了,真烦!");
            }
            
            System.out.println("睡醒了");
        }
        
    }
    View Code

     (5)案例:

           卖票案例。例子:cn.itcast3.demo  cn.itcast3.Ticket

    package cn.itcast3;
    /*
     * 线程安全问题:
     *         多个窗口卖指定个数的票
     *         3个窗口卖100张票
     *         票:共享数据
     *         窗口:线程
     */
    public class Demo {
    
        public static void main(String[] args) {
            
            Ticket ticket = new Ticket();
            
            Thread thread = new Thread(ticket,"唐嫣");
            Thread thread2 = new Thread(ticket,"柳岩");
            Thread thread3 = new Thread(ticket,"高圆圆");
            
            thread.start();
            thread2.start();
            thread3.start();
        }
    
    }
    View Code
    package cn.itcast3;
    /*
     * 票类(线程执行的目标):执行买票动作
     */
    public class Ticket implements Runnable {
    
        int number = 100; //应该放在成员变量的位置,实现三个对象的数据共享
        Object o = new Object();
        
        @Override
        public void run() {
            
            while(true) {
                synchronized(o) {
                
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    //如果有票,就卖票
                    if(number>0) {
                        //卖票
                        System.out.println(Thread.currentThread().getName()+":"+number);
                        number--;
                    }
                }
            }
        }
    }
    View Code

           线程安全问题:

               怎么产生的:

                  A:多线程环境

                  B:有共享数据

                  C:多条语句操作共享数据

           怎么解决:

               把C步骤给锁起来。

           两种方案:

               a:同步代码块

                   synchronized(锁对象) {

                      一个原子性操作

                  }

               注意:几个线程需要使用相同的锁对象进行同步操作,使用不同的锁是无法完成同步操作的。

               例子:cn.itcast3.demo  cn.itcast3.Ticket

    package cn.itcast3;
    /*
     * 线程安全问题:
     *         多个窗口卖指定个数的票
     *         3个窗口卖100张票
     *         票:共享数据
     *         窗口:线程
     */
    public class Demo {
    
        public static void main(String[] args) {
            
            Ticket ticket = new Ticket();
            
            Thread thread = new Thread(ticket,"唐嫣");
            Thread thread2 = new Thread(ticket,"柳岩");
            Thread thread3 = new Thread(ticket,"高圆圆");
            
            thread.start();
            thread2.start();
            thread3.start();
        }
    
    }
    View Code
    package cn.itcast3;
    /*
     * 票类(线程执行的目标):执行买票动作
     */
    public class Ticket implements Runnable {
    
        int number = 100; //应该放在成员变量的位置,实现三个对象的数据共享
        Object o = new Object();
        
        @Override
        public void run() {
            
            while(true) {
                synchronized(o) {
                
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    //如果有票,就卖票
                    if(number>0) {
                        //卖票
                        System.out.println(Thread.currentThread().getName()+":"+number);
                        number--;
                    }
                }
            }
        }
    }
    View Code

               b:同步方法

                  把synchronized添加到方法声明上。返回值前。例如:public synchronized void method() {}

                  例子:cn.itcast4.demo  cn.itcast4.Ticket

    package cn.itcast4;
    /*
     * 线程安全问题:
     *         多个窗口卖指定个数的票
     *         3个窗口卖100张票
     *         票:共享数据
     *         窗口:线程
     */
    public class Demo {
    
        public static void main(String[] args) {
            
            Ticket ticket = new Ticket();
            
            Thread thread = new Thread(ticket,"唐嫣");
            Thread thread2 = new Thread(ticket,"柳岩");
            Thread thread3 = new Thread(ticket,"高圆圆");
            
            thread.start();
            thread2.start();
            thread3.start();
        }
    
    }
    View Code
    package cn.itcast4;
    /*
     * 票类(线程执行的目标):执行买票动作
     * 
     * 同步方法:
     *         在方法上,返回值前,声明synchronized定义同步方法。
     *         该方法的锁为所在对象。
     */
    public class Ticket implements Runnable {
    
        int number = 100;
        Object o = new Object();
        
        @Override
        public void run() {
            
            while(true) {
                if(number%2==0) {  //当票数为偶数时
                    synchronized(this) {   //当前不变的对象,即ticket
                        
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                        //如果有票,就卖票
                        if(number>0) {
                            //卖票
                            System.out.println(Thread.currentThread().getName()+":"+number);
                            number--;
                        }
                    }
                }else {
                    method();
                }
            }
        }
        
        public synchronized void method() {  //在方法上,返回值前,声明synchronized定义同步方法。
                                                 //该方法的锁为所在对象。
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //如果有票,就卖票
            if(number>0) {
                //卖票
                System.out.println(Thread.currentThread().getName()+":"+number);
                number--;
            }
        }
    }
    View Code

               c.静态同步方法

                   将方法所在类作为默认所,即XX.class

                  例子:cn.itcast5.demo  cn.itcast5.Ticket

    package cn.itcast5;
    /*
     * 线程安全问题:
     *         多个窗口卖指定个数的票
     *         3个窗口卖100张票
     *         票:共享数据
     *         窗口:线程
     */
    public class Demo {
    
        public static void main(String[] args) {
            
            Ticket ticket = new Ticket();
            
            Thread thread = new Thread(ticket,"唐嫣");
            Thread thread2 = new Thread(ticket,"柳岩");
            Thread thread3 = new Thread(ticket,"高圆圆");
            
            thread.start();
            thread2.start();
            thread3.start();
        }
    
    }
    View Code
    package cn.itcast5;
    /*
     * 票类(线程执行的目标):执行买票动作
     * 
     * 静态同步方法:
     *         在方法上,返回值前,声明static synchronized定义静态同步方法。
     *         该方法的锁为所在的类对象。
     */
    public class Ticket implements Runnable {
    
        static int number = 100;
        Object o = new Object();
        
        @Override
        public void run() {
            
            while(true) {
                if(number%2==0) {
                    synchronized(Ticket.class) {  //类对像
                        
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                        //如果有票,就卖票
                        if(number>0) {
                            //卖票
                            System.out.println(Thread.currentThread().getName()+":"+number);
                            number--;
                        }
                    }
                }else {
                    method();
                }
            }
        }
        
        public static synchronized void method() {  //类对像
            
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            //如果有票,就卖票
            if(number>0) {
                //卖票
                System.out.println(Thread.currentThread().getName()+":"+number);
                number--;
            }
        }
    }
    View Code

    (6)Java同步机制的优缺点:

                a:优点:解决了多线程安全问题

                b:缺点:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。对于一个简单操作,单线程速度更快。

    (7)多线程的优缺点

            多线程并不提高某个程序的执行速度,仅仅是提高了CPU的使用率。

           图1:多线程示意图

           图2:多线程现率高

           图3:多线程状态图

       

    2:单例设计模式(理解 面试)

    (1)保证类在内存中只有一个对象。

    (2)怎么保证:

           A:构造私有

           B:自己造一个对象

           C:提供公共访问方式

     (3)两种方式:

           A:懒汉式(面试)

               public class Student {

                  private Student(){}

                  private static Student s = null;

                  public synchronized static Student getStudent() {

                      if(s == null) {

                         s = new Student();

                      }

                      return s;

                  }

               }

           B:饿汉式(开发)

               public class Student {

                  private Student(){}

                  private static Student s = new Student();

                  public static Student getStudent() {

                      return s;

                  }

               }

     (4)JDK的一个类本身也是单例模式的。

           Runtime

  • 相关阅读:
    【2018.05.05 C与C++基础】C++中的自动废料收集:概念与问题引入
    【2018.04.27 C与C++基础】关于switch-case及if-else的效率问题
    【2018.04.19 ROS机器人操作系统】机器人控制:运动规划、路径规划及轨迹规划简介之一
    March 11th, 2018 Week 11th Sunday
    March 10th, 2018 Week 10th Saturday
    March 09th, 2018 Week 10th Friday
    March 08th, 2018 Week 10th Thursday
    March 07th, 2018 Week 10th Wednesday
    ubantu之Git使用
    AMS分析 -- 启动过程
  • 原文地址:https://www.cnblogs.com/hezhiyao/p/7614950.html
Copyright © 2011-2022 走看看