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

  • 相关阅读:
    SQL SERVER 2008的元数据视图
    SQL Server 2008 中的 XML 功能
    SQL SERVER 2008的层次结构支持
    C#打包程序
    SQL SERVER 2008的top增强
    SQL SERVER导出数据字典
    SQL SERVER 2008的转置函数PIVOT
    SQL SERVER 2008的SQLCMD模式
    SQL SERVER 2008传递表值参数
    SQL Server 2005导出表中数据的SQL脚本形式(即INSERT语句)
  • 原文地址:https://www.cnblogs.com/hezhiyao/p/7614950.html
Copyright © 2011-2022 走看看