所谓的线程就是程序的执行线路。平时我们所写的程序几乎都是单线程的,即程序的执行路径只有一个。但是,在许多应用中单线程是不足以满足我们的要求的。比如:mp3中的功能,如果用单线程去实现,只能播完歌曲之后再显示歌词或者其他,显然不行,我们要求的是边播放歌曲边滚动歌词。这就要用到了我们的多线程,以达到多个功能并发执行。

   在我们平时的程序运行时,主要自启动了两个线程:

   ◆main主线程,调用main方法,执行main方法

   ◆GC线程:垃圾回收机制,主要用于main线程运行时运行,回收程序之中产生的垃圾

  一:线程的构造

   1:继承自Thread的线程类  线程名称  = new 继承自Thread的线程类();-->创建了一个继承自Thread的线程类

   2:Thread 线程名称  = new Thread (实现了Runnable接口的线程类);-->创建一个已经实现了Runnable接口的线程类

  二:如何写多线程?

 1:继承自Thread类,重写run方法,然后调用Thread的start方法启动这个新线程

public class TestThread {
    public static void main(String[] args) {
        MyThread m = new MyThread();//创建自己定义的线程对象
        m.start();//启动这个线程对象用start
        //m.run();相当于方法的调用,并没有开启新线程
        for(int i =0;i<10;i++){
            System.out.println("main-->"+(i+1));
        }
    }
}
class MyThread extends Thread{//单独定义一个类,继承自Thread类,重写run方法,实现多线程
    @Override
    public void run() {
        for(int i =0;i<10;i++){
            System.out.println("run-->"+(i+1));
        }
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
}

   结果:

main-->1
run-->1
main-->2
run-->2
main-->3
run-->3
main-->4
run-->4
main-->5
run-->5
main-->6
run-->6
main-->7
run-->7
main-->8
run-->8
main-->9
run-->9
main-->10
run-->10

   结果分析:从结果中可以发现,每次运行这个程序,结果可能不唯一,这是因为程序的执行需要CPU参与, 谁得到了执行权,谁的线程可以运行。main线程和自己创建的线程之间交替进行,也可以说是一种乱序执行,这就是我们所说的多线程之间的乱序执行,那单线程怎么执行的呢?

   单线程也就是我们平时所编写的普通程序,如下:

public class TestThread {
    public static void main(String[] args) {
        MyThread m = new MyThread();//创建自己定义的线程对象
        //m.start();//启动这个线程对象用start
        m.run();//相当于方法的调用,并没有开启新线程,仍是单线程
        for(int i =0;i<10;i++){
            System.out.println("main-->"+(i+1));
        }
    }
}
class MyThread extends Thread{//单独定义一个类,继承自Thread类,重写run方法,实现多线程
    @Override
    public void run() {
        for(int i =0;i<10;i++){
            System.out.println("run-->"+(i+1));
        }
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
}

   结果:

run-->1
run-->2
run-->3
run-->4
run-->5
run-->6
run-->7
run-->8
run-->9
run-->10
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10

   结果分析:细心的会发现,这个程序只和上边的那个程序有一句之差,而仅仅是这一句之差,让他变成了单线程,这个程序无论执行多少次,结果只有这一个,这就说明:单线程内部顺序执行

  2:实现Runnable接口,实现接口中的run方法,创建对象,作为Thread构造的参数,调用thread的start方法启动一个新线程。

public class MyRunnable {
    public static void main(String[] args) {
        MyRun m = new MyRun();//创建实现Runnable接口线程的对象
        Thread th = new Thread(m);//作为参数传递给线程
        th.start();//线程的启动   
        for(int i = 0;i<100;i++){
            System.out.println("main-->"+(i+1));
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
        }
    }
}
class MyRun implements Runnable{//线程的第二种创建方法,实现Runnable接口
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println("run-->"+(i+1));
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
        }
    }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
}

   结果:结果仍然同第一种创建线程的乱序结果(因为是乱序,结果不唯一,可自行试试)

  三:线程的常用方法

   1:start():启动一个新线程,如“线程.start()”这样使用

   2:run():创建线程时,要重写的方法,也是线程启动后运行的方法

   3:Thread.currentThread():获得当前线程

   4:setName(String name):设置线程名称,也可以在创建实现Runnable接口的类对象的参数中传递。

   5:getName():获得线程名称,主线程的名字默认为main,其余线程的默认名字形式为:Thread-0,Thread-1,Thread-2...

public class MyRunnable {
    public static void main(String[] args) {
        MyRun m = new MyRun();//创建实现Runnable接口线程的对象
        Thread th = new Thread(m);//作为参数传递给线程
        th.start();//线程的启动
        th.setName("天津");//给线程命名
        Thread.currentThread().setName("哈尔滨");//给当前线程main命名
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                                                                                                                                                                                                       
        }
    }
}
class MyRun implements Runnable{//线程的第二种创建方法,实现Runnable接口
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                                                                                                                                                                                                       
        }
    }
                                                                                                                                                                                                                                                                                                                                               
}

   结果:图中的结果只是截取的,这里要说明的是以上5个方法的使用。任然是乱序执行。

天津-->77
哈尔滨-->90
天津-->78
哈尔滨-->91
天津-->79
哈尔滨-->92
天津-->80
哈尔滨-->93

6:getPriority()setPriority():得到和设置线程的优先级。优先级范围:1-10。默认为5。优先级也就是谁的优先级高谁就有更大的可能性运行,所以低优先级的线程并不是不执行,只是没有那么大的机会被执行。在资源不足的情况下有所体现。

public class TestPerority {
    public static void main(String[] args) {
        Run m = new Run();
                                                                                                                                                                                                                                                                                                                       
        Thread th1 = new Thread(m);
        th1.setPriority(10);//设置线程1 的优先级为10
        th1.start();
                                                                                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                                       
        Thread th2 = new Thread(m);
        th2.setPriority(1);//设置线程2 的优先级为1
        th2.start();
                                                                                                                                                                                                                                                                                                                       
    }
}
class Run implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<1000;i++){//设置的大一点,看出的效果会大一点
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                                                                                                                                                                           
        }
    }
                                                                                                                                                                                                                                                                                                                   
}

   结果:可以从结果中看出线程0的优先级高,当他执行到83时,线程1才执行到73。结果仍为乱序。

Thread-0-->83
Thread-1-->73
Thread-0-->84
Thread-1-->74
Thread-0-->85
Thread-1-->75

   7:sleep():让线程休眠(停止运行)一段时间

public class TestSleep {
    public static void main(String[] args) {
        MySleep m = new MySleep();
        Thread th = new Thread(m);
        th.start();
                                                                                                                                                                                                                                                                   
    }
}
class MySleep implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
            Thread.sleep(1000);//让线程停止1秒输出一个,停止1秒输出一个
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            System.out.println(Thread.currentThread().getName() + "-->"
                    + (i + 1));
        }
    }
}

   执行效果:线程每隔1秒输出一个数,直到输出到100为止。

   8:join():当线程A运行的时候,若线程Bjoin() 进来的话,则暂停A的执行,先执行B,直到B执行结束之后,才继续开始A的执行。

public class Testjoin {
    public static void main(String[] args) {
        MyJoin m = new MyJoin();
        Thread th = new Thread(m);
        th.start();
        try {
            //在main中把th添加进来,只有th执行完毕之后才开始执行main
            th.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
                                                                                                                                                                                                                                                      
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                                                                                                          
        }
    }
}
class MyJoin implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                                                                                                          
        }
    }
                                                                                                                                                                                                                                                  
}

  结果:

Thread-0-->1
。。。。。。
Thread-0-->97
Thread-0-->98
Thread-0-->99
Thread-0-->100
main-->1
main-->2
main-->3
main-->4
main-->5
。。。。。。
main-->100

结果分析:这个程序如果去掉try-catch块中的内容,执行效果和第二个大问题中的第一点一样,应为乱序执行,而加入了join方法之后导致,自己创建的线程先执行,执行结束后才执行main线程。

    9:yield():让位,我把执行权先让出来,大家抢,谁抢到了谁执行,抢不过我,就我执行。

public class TestYeild {
    public static void main(String[] args) {
        MyYeild m = new MyYeild();
        Thread th = new Thread(m);
        th.start();   
        for(int i = 0;i<1000;i++){
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                            
        }
    }
}
class MyYeild implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<1000;i++){
            System.out.println("让你一下");
            //让你一下,你抢得过我你就执行,否则还是我执行
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+"-->"+(i+1));
                                                                                                                                                                            
        }
    }
                                                                                                                                                                    
}

   结果:图中结果为截取的。

main-->958
Thread-0-->633
让你一下
main-->959
main-->960
main-->961
main-->962
main-->963
main-->964
main-->965
main-->966
main-->967
main-->968
main-->969
main-->970
main-->971
main-->972
main-->973
Thread-0-->634
让你一下
Thread-0-->635

   结果分析:线程让位了一下,导致程序结果中的一段如图所示,说明在某一时刻,main线程抢过了自己创建线程的执行权。

   10:setDaemon(boolean bool):将线程设置为守护线程。守护线程一般用于为其他线程提供服务。如GC是一个典型的守护线程。守护线程的特点是:他会随着其他非守护线程结束而结束,且只能在调用start方法之前使用。isDaemon()方法用于判断一个线程是不是守护线程。

public class TestDemo {
    public static void main(String[] args) {
        Demo demo = new Demo();
        Thread th = new Thread(demo);
        th.setDaemon(true);//在调用start之前设置为守护线程
        th.start();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "-->"
                    + (i + 1));
        }
    }
}
class Demo implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("我是守护线程");
        }
    }
}

   结果:

我是守护线程
我是守护线程
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
我是守护线程
我是守护线程

   结果分析:图中的结果是因为守护线程随着主线程的运行而运行,而主线程运行结束之后,通知虚拟机,我结束了,而在通知的这一段时间之内,守护线程又执行了一会,说以就没有马上结束。

   线程还有许多应用,我们明天继续哈...w_0014.gif