zoukankan      html  css  js  c++  java
  • 多线程

    1.1  线程概述

           在计算机中,所有应用都是有CPU执行的,一个CPU在某个时间点只能运行一个程序——即一个进程。

           操作系统的每一个进程都只是存在一个线程,即当一个Java程序启东市,线程运行main()方法中的代码。要在程序中实现多段代码交替运行,这需要创建多个线程——即多线程。多线程进程一样,也是有CPU轮流执行的,是不给CPU运行的速度很块。

    1.2 线程的创建

           Java提供两种多线程实现方法:

      1)    继承java.lang包下的Tread类,覆盖Thread的run()方法,在run()中实现运行在线程上的代码;

      2)    实现java.lang.Runnable接口,在run()中实现运行在线程上的代码。

    1.2.1 继承Thread类的创建多线程

           JDK提供一个线程类Thread,继承该类,重写run方法,可实现多线程,并且提供一个start()方法用于启动线程,程序启动后,线程会自动调用run()方法。

     1 public class Example01 {
     2     
     3     public static void main(String[] args) {
     4         MyThread myThread=new MyThread();
     5         myThread.start();
     6         while(true){
     7             System.out.println("main()方法在运行");
     8         }
     9         
    10     }
    11     public  static class MyThread extends Thread{
    12         public void run() {
    13             while(true){
    14                 System.out.println("MyThread类的run()方法在运行");
    15             }
    16         }
    17     }
    18 
    19 
    20 }

      结果分析:两个while循环中的打印语句轮流执行。即main()方法和MyTread()类的中的Run()语句可以同时运行。

    1.2.2 实现Runable接口创建多线程

           继承Thread类的创建多线程有一定局限性,一个类一旦继承某个父类就无法继承其他类(Java只支持单继承)。

     1 public class Example02 {
     2     public static void main(String[] args) {
     3         MyThread myThread=new MyThread();//创建MyThread的实例对象
     4         Thread thread=new Thread(myThread);//创建线程对象
     5         thread.start();
     6         while(true){
     7             System.out.println("main()方法在运行");
     8         }     
     9     }
    10     public  static class MyThread implements Runnable{
    11         public void run() {//线程代码块,当调用Start()方法时,线程从此处开始执行
    12             while(true){
    13                 System.out.println("MyThread类的run()方法在运行");
    14             }
    15         }
    16     }
    17 }

      结果分析:两个while循环中的打印语句轮流执行。即main()方法和MyTread()类的中的Run()语句可以同时运行。

    1.2.3 两种多线程比较

           以售票大厅为类:售票大厅有四个窗口,共计售卖100张票。

    A)   继承Thread类的创建多线程

     1 public class Example03 {
     2     public static class TicketWindow extends Thread{
     3         private int tickets=100;
     4         public void run() {
     5             while(true) {        //通过死循环打印语句
     6                 if(tickets>0) {
     7                     Thread th=Thread.currentThread();//获取当前线程
     8                     String th_name=th.getName();  //获取当前线程的名字
     9                     System.out.println(th_name+"正在发售第"+tickets--+"张票");
    10                 }
    11             }
    12         }
    13     }
    14     public static void main(String[] args) {
    15         new TicketWindow().start();//创建一个线程对象TicketWindow()并开启
    16         new TicketWindow().start();//创建一个线程对象TicketWindow()并开启
    17         new TicketWindow().start();//创建一个线程对象TicketWindow()并开启
    18         new TicketWindow().start();//创建一个线程对象TicketWindow()并开启
    19     }
    20 }

      运行结果:Thread-0正在发售第100张票

    Thread-3正在发售第100张票

    Thread-2正在发售第100张票

    Thread-1正在发售第100张票

    Thread-2正在发售第99张票

    Thread-3正在发售第99张票

    Thread-0正在发售第99张票

    Thread-3正在发售第98张票

    Thread-2正在发售第98张票

    Thread-1正在发售第99张票

    Thread-2正在发售第97张票

    Thread-3正在发售第97张票

    Thread-0正在发售第98张票

    …….

              分析可知:线程会自动编号,,用户创建的第一个线程为“Thread-0”,从0开始编号。但是四个线程都是从100章票开始往下减,独立出来自己的资源,且四个线程每次执行的次序都是随机的。(但是这种运行结果是不合理的)。

    B)    实现Runable接口创建多线程

     1 public class Example04 {
     2     public static class TicketWindow implements Runnable{
     3         private int tickets=100;
     4         public void run() {
     5             while(true) {        //通过死循环打印语句
     6                 if(tickets>0) {
     7                     Thread th=Thread.currentThread();//获取当前线程
     8                     String th_name=th.getName();  //获取当前线程的名字
     9                     System.out.println(th_name+"正在发售第"+tickets--+"张票");
    10                 }
    11             }
    12         }
    13     }
    14     public static void main(String[] args) {
    15         TicketWindow tw =new TicketWindow();//创建TicketWindow实例对象tw
    16         new Thread(tw,"窗口1").start();//创建线程对象并命名为窗口1,开启线程
    17         new Thread(tw,"窗口2").start();
    18     }
    19 }

      分析:代码只创建了一个ThickWindow对象,然后创建了四个线程,四个线程都去调用这个TicketWindow对象中的run()方嘎,确保四个线程访问的是同一个tickets变量,共享100章车票。

      综上;Runnable接口相对于Threadgen有显著好处

           1)适合多个相同程序去处理同个资源的情况,把线程同程序代码、数据有效的分离;

           2)可以避免由于Java的单继承性带来的局限性;

    1.3 线程的调度

           Java虚拟机会按照特定的机制为程序中的每个线程分配CPU的使用权,这种机制被称作线程的调度。

           线程的电镀有两种模型:分时调度模型和抢占式调度模型

      A)   分时调度模型:所有线程轮流获得CPU的使用权,并且平均分配每个下次占用的CPU的时间片

      B)    抢占式调度模型:可让运行迟中优先级高的线程先占用CPU,对于优先级相同的线程。随机选取一个线程使其占用CPU

    1.3.1 线程的优先级

           对线程进行调度,可以设置线程的优先级。线程优先级用1-10的整数表示,数字越大优先级越高。

    表5-1 Thread类的优先级常量

    Threadl类的静态常量

    功能描述

    Static int MAX_PRIORITY

    表示线程的最高优先级,10

    Static int MIN_PRIORITY

    表示线程的最低优先级,0

    Static int NORM_PRIORITY

    表示线程的普通优先级,5

           处于就绪状态的每个线程独有自己的优先级,main线程具有普通优先级。可以通过Thread类的setPriority(int newPriority)方法对其进行设置,该方法中的参数newPriority为1-10的整数或者Thread类的三个静态常量。

     1 public class Example5 {
     2     public static void main(String[] args) {
     3         Thread maxPriority=new Thread(new MaxPriority(),"优先级最高的线程");//创建线程对象
     4         Thread minPriority=new Thread(new MinPriority(),"优先级最低的线程");
     5         //设置优先级
     6         maxPriority.setPriority(10);
     7         minPriority.setPriority(Thread.MIN_PRIORITY);
     8         //开启两个线程
     9         minPriority.start();
    10         maxPriority.start();    
    11     }
    12     //定义类MaxPriority实现Runnable接口
    13     public  static class MaxPriority implements Runnable{
    14         public void run() {//线程代码块,当调用Start()方法时,线程从此处开始执行
    15             for(int i=0;i<10;i++) {
    16                 System.out.println(Thread.currentThread().getName()+"正在输出"+i);
    17             }
    18         }    
    19     }
    20     //定义类MinPriority实现Runnable接口
    21     public  static class MinPriority implements Runnable{
    22         public void run() {//线程代码块,当调用Start()方法时,线程从此处开始执行
    23             for(int i=0;i<10;i++) {
    24                 System.out.println(Thread.currentThread().getName()+"正在输出"+i);
    25             }
    26         }    
    27     }
    28 }

    1.3.2 线程休眠、让步、插队

      A)线程休眠:Java提供一个静态方法sleep(long millis),该方法可以让当前的正在执行的线程暂停一段时间,进入休眠等待状态。

           Sleep(long millis)方法声明抛出InterruptedException异常,英雌在调用该方法时应该不活异常,或者声明抛出异常。

    B)线程让步:Java提供yield()方法来实现,该方法和sleep()方法相似,都可让当前正在运行的线程暂停。它的作用是是将线程转换成就绪状态,让系统调度器可以重新调度一次。

      C)线程插队:在线程中也提供一个方法join()使得线程可以“插队”。当在某个线程调用其它线程的join()方法时,调用的线程将被堵塞,直到被join()方法加入的线程执行完成后它才可以继续执行。

      join()方法声明抛出InterruptedException异常,英雌在调用该方法时应该不活异常,或者声明抛出异常。

     1 public class Example06 {
     2     public static void main(String[] args) throws Exception {
     3         Thread t=new Thread(new MaxPriority(),"线程一");//创建线程对象
     4         t.start();
     5         for(int i=0;i<10;i++) {
     6             System.out.println(Thread.currentThread().getName()+"正在输出"+i);
     7             if(i==2) {
     8                 t.join();
     9             }
    10             Thread.sleep(500);
    11         }    
    12     }
    13     //定义类MaxPriority实现Runnable接口
    14         public  static class MaxPriority implements Runnable{
    15             public void run() {//线程代码块,当调用Start()方法时,线程从此处开始执行
    16                 for(int i=0;i<10;i++) {
    17                     System.out.println(Thread.currentThread().getName()+"正在输出"+i);
    18                     try {
    19                         Thread.sleep(500);
    20                     } catch (InterruptedException e) {
    21                         // TODO Auto-generated catch block
    22                         e.printStackTrace();
    23                     }
    24                 }
    25             }    
    26         }
    27 }

    分析运行结果:发现当main中的循环变量变为2是,调用t线程的join()方法,直到t线程执行完毕以后再执行main线程。

  • 相关阅读:
    CSS魔法堂:重拾Border之——更广阔的遐想
    CSS魔法堂:重拾Border之——不仅仅是圆角
    CSS魔法堂:重拾Border之——图片作边框
    CSS魔法堂:重拾Border之——解构Border
    CSS3魔法堂:说说Multi-column Layout
    CSS魔法堂:"那不是bug,是你不懂我!" by inline-block
    CSS魔法堂:小结一下Box Model与Positioning Scheme
    CSS魔法堂:说说Float那个被埋没的志向
    CSS魔法堂:你一定误解过的Normal flow
    CSS魔法堂:Absolute Positioning就这个样
  • 原文地址:https://www.cnblogs.com/tianliang94/p/10065979.html
Copyright © 2011-2022 走看看