zoukankan      html  css  js  c++  java
  • JAVA笔记14-线程

    一、概念

      线程:是一个程序里面不同的执行路径,每一个分支都叫线程。到现在为止我们所讲的程序分支只有一个,即main方法,称作主线程。

      进程:class文件,exe文件。程序的执行过程:程序放入代码区(进程产生,准备开始执行,进程是静态的概念),平时所说的“进程的执行”是指进程中主线程(main)的执行,实际运行得都是线程。

      Windows Linux Unix操作系统是支持多进程、多线程的,Dos是只支持单进程的。一个时间点上一个cpu只有一个线程在执行,CPU很快,看起来像是同时运行。真正的多线程:多个CPU,双核。

    二、线程的产生方式

       Java的线程是通过java.lang.Thread类实现的。可以通过创建Thread的实例来创建新的线程。通过调用Thread类的start()方法来启动一个线程。VM启动时会有一个由主方法所定义的线程。每个线程都是通过某个特定Thread对象所对应的run()方法来完成其操作的,run()方法称为线程体。

      可以有两种方式创建新的线程:

    方法一:(建议使用此法)

    (1)定义线程类实现Runnable接口

    (2)Thread myThread = new Thread(target)//target为Runnable接口类型

    (3)Runnable中只有一个方法:public void run();//用以定义线程运行体

    (4)使用Runnable接口可以为多个线程提供共享的数据

    (5)在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法:public static Thread currentThread()//获得当前线程的引用

    方法一举例:要new Thread对象来调用start方法启动线程,之后产生分支,主线程和分支线程并行执行;但是如果直接调用run方法,就是方法调用,还是单线程。

    public class TestThread1{
        public static void main(String args[]){
            Runner1 r = new Runner1();
            Thread t = new Thread(r);
            t.start();//不可以直接用r.start();或r.run()
            for(int i=0; i<100; i++){
                System.out.println("Main Thread:---------------------"+i);
            }
        }
    }
    class Runner1 implements Runnable{
        public void run(){
            for(int i=0; i<100; i++){
                System.out.println("Runner1:"+i);
            }
        }
    }

    方法二:

    (1)可以定义一个Thread的子类并重写其run方法。如:class MyThread extends Thread{public void run(){……}}

    (2)然后生成该类的对象:MyThread myThread = new MyThread(……)

    方法二举例:

    public class TestThread1{
        public static void main(String args[]){
            Runner1 r = new Runner1();
            r.start();//可以直接用r.start();但不可以r.run()
            for(int i=0; i<100; i++){
                System.out.println("Main Thread:---------------------"+i);
            }
        }
    }
    class Runner1 extends Thread{
        public void run(){
            for(int i=0; i<100; i++){
                System.out.println("Runner1:"+i);
            }
        }
    }

    三、线程状态转换

      start之后进入“就绪”,等待cpu时间片,时间片到达后进入“运行”,阻塞事件发生(如IO),事件解决则进入“就绪”

    线程控制的基本方法:

    注:就绪,运行,阻塞属于“活着”。优先级高,则分配的时间多。

    1、sleep方法:使得当前线程休眠(暂时停止执行millis毫秒)

    可以调用Thread的静态方法:public static void sleep(long millis) throws InterruptedException,因为抛异常所以必须要写try catch。

    由于是静态方法,所以可以由类名直接调用Thread.sleep(…);

    sleep方法举例:在哪个线程调用sleep就是让这个线程睡眠,如第7行的sleep方法是让主线程睡眠。而第10行是主线程睡眠10000ms后,来打断睡眠1000ms中的MyThread线程,导致该子线程抛异常。catch到异常后,该子线程结束。

     1 import java.util.*;//因为是用Date()
     2 public class TestInterrupt{
     3     public static void main(String args[]){
     4         MyThread thread = new MyThread();
     5         thread.start();
     6         try{
     7             Thread.sleep(10000);
     8         }catch(InterruptedException e){
     9         }
    10         thread.interrupt();//Interrupt不是让子线程结束的好方法。stop更不好,尽量也不要使用
    11     }
    12 }
    13 class MyThread extends Thread{
    14     public void run(){
    15         while(true){
    16             System.out.println("==="+new Date()+"===");
    17             try{
    18                 sleep(1000);
    19             }catch(InterruptedException e){
    20                 return;
    21             }
    22         }
    23     }
    24 }

    输出:

    ===Mon Apr 21 17:16:28 CST 2014===
    ===Mon Apr 21 17:16:29 CST 2014===
    ===Mon Apr 21 17:16:30 CST 2014===
    ===Mon Apr 21 17:16:31 CST 2014===
    ===Mon Apr 21 17:16:32 CST 2014===
    ===Mon Apr 21 17:16:33 CST 2014===
    ===Mon Apr 21 17:16:34 CST 2014===
    ===Mon Apr 21 17:16:35 CST 2014===
    ===Mon Apr 21 17:16:36 CST 2014===
    ===Mon Apr 21 17:16:37 CST 2014=== 

    注意:Interrupt不是让子线程结束的好方法。stop更不好,尽量也不要使用,建议这样控制flag使run方法结束,run方法结束则线程结束。

    import java.util.*;//因为是用Date()
    public class TestInterrupt{
        public static void main(String args[]){
            MyThread thread = new MyThread();
            thread.start();
            try{
                Thread.sleep(10000);
            }catch(InterruptedException e){
            }
            thread.shutDown();
        }
    }
    class MyThread extends Thread{
        private boolean flag = true ;
        public void run(){
            while(flag==true){
                System.out.println("==="+new Date()+"===");
                try{
                    sleep(1000);
                }catch(InterruptedException e){
                    return;
                }
            }
        }
        public void shutDown(){
            flag = false;
        }
    }

    注意:重写的方法不能比父类抛出不同的异常,所以不能在run方法抛出异常。

    2、join方法:合并某个线程

    join方法举例:第7行,join是合并两个线程,相当于方法调用。程序先执行子线程,主线程再执行。

     1 import java.util.*;//因为是用Date()
     2 public class TestJoin{
     3     public static void main(String args[]){
     4         MyThread t = new MyThread("abcde");
     5         t.start();
     6         try{
     7             t.join();
     8         }catch(InterruptedException e){
     9         }
    10         for(int i=1; i<=10; i++){
    11             System.out.println("I am main thread----"+i);
    12         }
    13     }
    14 }
    15 
    16 class MyThread extends Thread{
    17     MyThread(String s){
    18         super(s);
    19     }
    20     public void run(){
    21         for(int i=1; i<=10; i++){
    22             System.out.println("I am "+getName()+"==="+i);
    23             try{
    24                 sleep(1000);
    25             }catch(InterruptedException e){
    26                 return;
    27             }
    28         }
    29     }
    30 }

    输出:

    I am abcde===1
    I am abcde===2
    I am abcde===3
    I am abcde===4
    I am abcde===5
    I am abcde===6
    I am abcde===7
    I am abcde===8
    I am abcde===9
    I am abcde===10
    I am main thread----1
    I am main thread----2
    I am main thread----3
    I am main thread----4
    I am main thread----5
    I am main thread----6
    I am main thread----7
    I am main thread----8
    I am main thread----9
    I am main thread----10

    3、yield方法:让出CPU,给其他线程执行的机会

    yeild方法举例:下面程序有三条路径(main,t1,t2),每次到10的倍数则让出cpu。不经常用。

     1 public class TestYeild{
     2     public static void main(String args[]){
     3         MyThread t1 = new MyThread("t1");
     4         MyThread t2 = new MyThread("t2");
     5         t1.start();
     6         t2.start();
     7     }
     8 }
     9 
    10 class MyThread extends Thread{
    11     MyThread(String s){
    12         super(s);
    13     }
    14     public void run(){
    15         for(int i=1; i<=100; i++){
    16             System.out.println("I am "+getName()+"==="+i);
    17             if(i%10==0){
    18                 yield();
    19             }
    20         }
    21     }
    22 }

    四、线程优先级(优先级高得到的cpu执行的时间片多)

      Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应调度哪个线程来执行。线程的优先级用数字表示,优先级范围1~10,默认是5。

    Thread.MIN_PRIORITY = 1

       Thread.MAX_PRIORITY = 10

       Thread.NORM_PRIORITY = 5

      使用下述方法获得或设置线程对象的优先级:

    int getPriority();

                           void setPriority(int newPriority);

    举例:t1的优先级高于t2,但并非等到t1执行完毕后t2才执行。

    public class TestPriority{
        public static void main(String args[]){
            Thread t1 = new Thread(new T1());
            Thread t2 = new Thread(new T2());
            t1.setPriority(Thread.NORM_PRIORITY+3);
            t1.start();
            t2.start();
        }
    }
    
    class T1 implements Runnable{
        public void run(){
            for(int i=1; i<=100; i++){
                System.out.println("T1:"+i);
            }
        }
    }
    class T2 implements Runnable{
        public void run(){
            for(int i=1; i<=100; i++){
                System.out.println("--------T2:"+i);
            }
        }
    }

    i<=1000时的部分输出:

    四、其他例子

    1、同一个线程对象,用来启动两个线程

    public class Test{
        public static void main(String args[]){
            Runner r = new Runner();
            Thread t1 = new Thread(r);
            Thread t2 = new Thread(r);
            t1.start();
            t2.start();
        }
    }
    
    class Runner implements Runnable{
        public void run(){
            for(int i=0; i<30; i++){
                System.out.println("No."+i);
            }
        }
    }

    2、currentThread是当前线程(this是当前对象)

    public class Test{
        public static void main(String args[]){
            Thread t = new Runner();
            t.start();
            for(int i=0; i<30; i++){
            System.out.println("MainThread:"+i);
            }
        }
    }
    
    class Runner extends Thread{
        public void run(){
            System.out.println(Thread.currentThread().isAlive());
            for(int i=0; i<30; i++){
                System.out.println("SubThread:"+i);
            }
        }
    }
  • 相关阅读:
    狄利克雷卷积
    洛谷P2044 [NOI2012]随机数生成器
    Miller Rabin算法详解
    BZOJ3667: Rabin-Miller算法
    洛谷P3383 【模板】线性筛素数(Miller_Rabin)
    洛谷P3806 【模板】点分治1
    BZOJ1468: Tree
    Android Camera调用过程分析
    安卓开发37:自定义的HorizontalScrollView类,使其pageScroll的时候焦点不选中
    Android抖动动画
  • 原文地址:https://www.cnblogs.com/seven7seven/p/3670272.html
Copyright © 2011-2022 走看看