多线程

来源:互联网 发布:手机怎样注册淘宝店铺 编辑:程序博客网 时间:2024/05/07 00:59

1:多线程(理解)
(1)多线程:一个应用程序有多条执行路径
进程:正在执行的应用程序
线程:进程的执行单元,执行路径
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径

    多进程的意义?        提高CPU的使用率    多线程的意义?        提高应用程序的使用率

(2)Java程序的运行原理及JVM的启动是多线程的吗?
A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
(3)多线程的实现方案(自己补齐步骤及代码 掌握)
A:继承Thread类

/* * 需求:我们要实现多线程的程序。 * 如何实现呢? *      由于线程是依赖进程而存在的,所以我们应该先创建一个进程出来。 *      而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。 *      Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。 *      但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。 *      由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西, *      然后提供一些类供我们使用。我们就可以实现多线程程序了。 * 那么Java提供的类是什么呢? *      Thread *      通过查看API,我们知道了有2中方式实现多线程程序。 *  * 方式1:继承Thread类。 * 步骤 *      A:自定义类MyThread继承Thread类。 *      B:MyThread类里面重写run()? *          为什么是run()方法呢? *      C:创建对象 *      D:启动线程 */public class MyThreadDemo {    public static void main(String[] args) {        // 创建线程对象        // MyThread my = new MyThread();        // // 启动线程        // my.run();        // my.run();        // 调用run()方法为什么是单线程的呢?        // 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果        // 要想看到多线程的效果,就必须说说另一个方法:start()        // 面试题:run()和start()的区别?        // run():仅仅是封装被线程执行的代码,直接调用是普通方法        // start():首先启动了线程,然后再由jvm去调用该线程的run()方法。        // MyThread my = new MyThread();        // my.start();        // // IllegalThreadStateException:非法的线程状态异常        // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。        // my.start();        // 创建两个线程对象        MyThread my1 = new MyThread();        MyThread my2 = new MyThread();        my1.start();        my2.start();    }}
    B:实现Runnable接口      
/* * 方式2:实现Runnable接口 * 步骤: *      A:自定义类MyRunnable实现Runnable接口 *      B:重写run()方法 *      C:创建MyRunnable类的对象 *      D:创建Thread类的对象,并把C步骤的对象作为构造参数传递 */public class MyRunnableDemo {    public static void main(String[] args) {        // 创建MyRunnable类的对象        MyRunnable my = new MyRunnable();        // 创建Thread类的对象,并把C步骤的对象作为构造参数传递        // Thread(Runnable target)        // Thread t1 = new Thread(my);        // Thread t2 = new Thread(my);        // t1.setName("林青霞");        // t2.setName("刘意");        // Thread(Runnable target, String name)        Thread t1 = new Thread(my, "林青霞");        Thread t2 = new Thread(my, "刘意");        t1.start();        t2.start();    }}

(4)线程的调度和优先级问题
A:线程的调度
a:分时调度
b:抢占式调度 (Java采用的是该调度方式)
B:获取和设置线程优先级
a:默认是5
b:范围是1-10

/* * 我们的线程没有设置优先级,肯定有默认优先级。 * 那么,默认优先级是多少呢? * 如何获取线程对象的优先级? *      public final int getPriority():返回线程对象的优先级 * 如何设置线程对象的优先级呢? *      public final void setPriority(int newPriority):更改线程的优先级。  *  * 注意: *      线程默认优先级是5。 *      线程优先级的范围是:1-10。 *      线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。 *       * IllegalArgumentException:非法参数异常。 * 抛出的异常表明向方法传递了一个不合法或不正确的参数。  *  */public class ThreadPriorityDemo {    public static void main(String[] args) {        ThreadPriority tp1 = new ThreadPriority();        ThreadPriority tp2 = new ThreadPriority();        ThreadPriority tp3 = new ThreadPriority();        tp1.setName("东方不败");        tp2.setName("岳不群");        tp3.setName("林平之");        // 获取默认优先级        // System.out.println(tp1.getPriority());        // System.out.println(tp2.getPriority());        // System.out.println(tp3.getPriority());        // 设置线程优先级        // tp1.setPriority(100000);        //设置正确的线程优先级        tp1.setPriority(10);        tp2.setPriority(1);        tp1.start();        tp2.start();        tp3.start();    }}
(5)线程的控制(常见方法)    A:休眠线程
public class ThreadSleep extends Thread {    @Override    public void run() {        for (int x = 0; x < 100; x++) {            System.out.println(getName() + ":" + x + ",日期:" + new Date());            // 睡眠            // 困了,我稍微休息1秒钟            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}
/* * 线程休眠 *      public static void sleep(long millis) */public class ThreadSleepDemo {    public static void main(String[] args) {        ThreadSleep ts1 = new ThreadSleep();        ThreadSleep ts2 = new ThreadSleep();        ThreadSleep ts3 = new ThreadSleep();        ts1.setName("林青霞");        ts2.setName("林志玲");        ts3.setName("林志颖");        ts1.start();        ts2.start();        ts3.start();    }}
    B:加入线程
public class ThreadJoin extends Thread {    @Override    public void run() {        for (int x = 0; x < 100; x++) {            System.out.println(getName() + ":" + x);        }    }}
/* * public final void join():等待该线程终止。  */public class ThreadJoinDemo {    public static void main(String[] args) {        ThreadJoin tj1 = new ThreadJoin();        ThreadJoin tj2 = new ThreadJoin();        ThreadJoin tj3 = new ThreadJoin();        tj1.setName("李渊");        tj2.setName("李世民");        tj3.setName("李元霸");        tj1.start();        try {            tj1.join();        } catch (InterruptedException e) {            e.printStackTrace();        }        tj2.start();        tj3.start();    }}
    C:礼让线程
/* * public static void yield():暂停当前正在执行的线程对象,并执行其他线程。  * 让多个线程的执行更和谐,但是不能靠它保证一人一次。 */public class ThreadYieldDemo {    public static void main(String[] args) {        ThreadYield ty1 = new ThreadYield();        ThreadYield ty2 = new ThreadYield();        ty1.setName("林青霞");        ty2.setName("刘意");        ty1.start();        ty2.start();    }}
    D:后台线程    E:终止线程(掌握)
/* * public final void stop():让线程停止,过时了,但是还可以使用。 * public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException。 */public class ThreadStopDemo {    public static void main(String[] args) {        ThreadStop ts = new ThreadStop();        ts.start();        // 你超过三秒不醒过来,我就干死你        try {            Thread.sleep(3000);            // ts.stop();            ts.interrupt();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
public class ThreadStop extends Thread {    @Override    public void run() {        System.out.println("开始执行:" + new Date());        // 我要休息10秒钟,亲,不要打扰我哦        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            // e.printStackTrace();            System.out.println("线程被终止了");        }        System.out.println("结束执行:" + new Date());    }}
(6)线程的生命周期(参照   线程生命周期图解.bmp)    A:新建    B:就绪    C:运行    D:阻塞    E:死亡

这里写图片描述
(7)电影院卖票程序的实现
A:继承Thread类

ublic class SellTicket extends Thread {    // 定义100张票    // private int tickets = 100;    // 为了让多个线程对象共享这100张票,我们其实应该用静态修饰    private static int tickets = 100;    @Override    public void run() {        // 定义100张票        // 每个线程进来都会走这里,这样的话,每个线程对象相当于买的是自己的那100张票,这不合理,所以应该定义到外面        // int tickets = 100;        // 是为了模拟一直有票        while (true) {            if (tickets > 0) {                System.out.println(getName() + "正在出售第" + (tickets--) + "张票");            }        }    }/* * 某电影院目前正在上映贺岁大片(红高粱,少林寺传奇藏经阁),共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。 * 继承Thread类来实现。 */public class SellTicketDemo {    public static void main(String[] args) {        // 创建三个线程对象        SellTicket st1 = new SellTicket();        SellTicket st2 = new SellTicket();        SellTicket st3 = new SellTicket();        // 给线程对象起名字        st1.setName("窗口1");        st2.setName("窗口2");        st3.setName("窗口3");        // 启动线程        st1.start();        st2.start();        st3.start();    }}
    B:实现Runnable接口
public class SellTicket implements Runnable {    // 定义100张票    private int tickets = 100;    @Override    public void run() {        while (true) {            if (tickets > 0) {                System.out.println(Thread.currentThread().getName() + "正在出售第"                        + (tickets--) + "张票");            }        }    }}/* * 实现Runnable接口的方式实现 */public class SellTicketDemo {    public static void main(String[] args) {        // 创建资源对象        SellTicket st = new SellTicket();        // 创建三个线程对象        Thread t1 = new Thread(st, "窗口1");        Thread t2 = new Thread(st, "窗口2");        Thread t3 = new Thread(st, "窗口3");        // 启动线程        t1.start();        t2.start();        t3.start();    }}
(8)电影院卖票程序出问题    A:为了更符合真实的场景,加入了休眠100毫秒。    B:卖票问题        a:同票多次        b:负数票(9)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)    A:是否有多线程环境    B:是否有共享数据    C:是否有多条语句操作共享数据(10)同步解决线程安全问题    A:同步代码块        synchronized(对象) {            需要被同步的代码;        }        这里的锁对象可以是任意对象。    B:同步方法        把同步加在方法上。        这里的锁对象是this    C:静态同步方法        把同步加在方法上。        这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
public class SellTicket implements Runnable {    // 定义100张票    private static int tickets = 100;    // 定义同一把锁    private Object obj = new Object();    private Demo d = new Demo();    private int x = 0;    //同步代码块用obj做锁//  @Override//  public void run() {//      while (true) {//          synchronized (obj) {//              if (tickets > 0) {//                  try {//                      Thread.sleep(100);//                  } catch (InterruptedException e) {//                      e.printStackTrace();//                  }//                  System.out.println(Thread.currentThread().getName()//                          + "正在出售第" + (tickets--) + "张票 ");//              }//          }//      }//  }    //同步代码块用任意对象做锁//  @Override//  public void run() {//      while (true) {//          synchronized (d) {//              if (tickets > 0) {//                  try {//                      Thread.sleep(100);//                  } catch (InterruptedException e) {//                      e.printStackTrace();//                  }//                  System.out.println(Thread.currentThread().getName()//                          + "正在出售第" + (tickets--) + "张票 ");//              }//          }//      }//  }    @Override    public void run() {        while (true) {            if(x%2==0){                synchronized (SellTicket.class) {                    if (tickets > 0) {                        try {                            Thread.sleep(100);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        System.out.println(Thread.currentThread().getName()                                + "正在出售第" + (tickets--) + "张票 ");                    }                }            }else {//              synchronized (d) {//                  if (tickets > 0) {//                      try {//                          Thread.sleep(100);//                      } catch (InterruptedException e) {//                          e.printStackTrace();//                      }//                      System.out.println(Thread.currentThread().getName()//                              + "正在出售第" + (tickets--) + "张票 ");//                  }//              }                sellTicket();            }            x++;        }    }//  private void sellTicket() {//      synchronized (d) {//          if (tickets > 0) {//          try {//                  Thread.sleep(100);//          } catch (InterruptedException e) {//                  e.printStackTrace();//          }//          System.out.println(Thread.currentThread().getName()//                      + "正在出售第" + (tickets--) + "张票 ");//          }//      }//  }    //如果一个方法一进去就看到了代码被同步了,那么我就再想能不能把这个同步加在方法上呢?//   private synchronized void sellTicket() {//          if (tickets > 0) {//          try {//                  Thread.sleep(100);//          } catch (InterruptedException e) {//                  e.printStackTrace();//          }//          System.out.println(Thread.currentThread().getName()//                      + "正在出售第" + (tickets--) + "张票 ");//          }//  }    private static synchronized void sellTicket() {        if (tickets > 0) {        try {                Thread.sleep(100);        } catch (InterruptedException e) {                e.printStackTrace();        }        System.out.println(Thread.currentThread().getName()                    + "正在出售第" + (tickets--) + "张票 ");        }}}class Demo {}
/* * A:同步代码块的锁对象是谁呢? *      任意对象。 *  * B:同步方法的格式及锁对象问题? *      把同步关键字加在方法上。 *  *      同步方法是谁呢? *          this *  * C:静态方法及锁对象问题? *      静态方法的锁对象是谁呢? *          类的字节码文件对象。(反射会讲) */public class SellTicketDemo {    public static void main(String[] args) {        // 创建资源对象        SellTicket st = new SellTicket();        // 创建三个线程对象        Thread t1 = new Thread(st, "窗口1");        Thread t2 = new Thread(st, "窗口2");        Thread t3 = new Thread(st, "窗口3");        // 启动线程        t1.start();        t2.start();        t3.start();    }}
(11)回顾以前的线程安全的类    A:StringBuffer    B:Vector    C:Hashtable    D:如何把一个线程不安全的集合类变成一个线程安全的集合类        用Collections工具类的方法即可。
public class ThreadDemo {    public static void main(String[] args) {        // 线程安全的类        StringBuffer sb = new StringBuffer();        Vector<String> v = new Vector<String>();        Hashtable<String, String> h = new Hashtable<String, String>();        // Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你        // 那么到底用谁呢?        // public static <T> List<T> synchronizedList(List<T> list)        List<String> list1 = new ArrayList<String>();// 线程不安全        List<String> list2 = Collections                .synchronizedList(new ArrayList<String>()); // 线程安全    }}
0 0
原创粉丝点击