Java线程

首先说依稀进程与线程的区别吧:进程即对操作系统而言,运行的某个程序,如QQEclipseJVM等都可以看作是一个进程,对于进程来说操作系统会为其分配一片独立的内存空间,进程是由很多个线程组成的,但是线程本身不会获取独立的内存空间,而是采用共享的方式,所以多进程之间的并发的健壮性一定会比多线程之间的并发性的健壮性好的,所谓健壮性也不过就是安全性,进程的内存空间彼此是独立的,而线程的内存空间是有依赖性的,所以又一个线程出错了,那么这个进程大概也就死掉了,我们现在写的java程序简单的都是单线程的,下面引入多线程的概念:

多线程扩展了多进程操作的概念,将任务的划分下降到了程序级别,使得各个程序似乎可以在同一个时间内执行多个任务,每个任务成为一个线程,能够同时运行多个线程的程序成为多线程程序。

使用多线程编程有以下优点:

*进程间不能共享内存,因为其实独立的内存空间,而线程间共享内存非常容易,但是一定要保证共享内存安全

*系统创建进程需要为改进程分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发效率高

*java语言内置多线程功能支持,而不是单纯作为递呈操作系统的调度方式,从而简化了java的多线程编程

201554189.jpg

   多线程编程的实现大概有两种方式:

一:通过继承Thread类来创建线程

Thread();创建一个线程;

Thread(Runnable target):创建一个线程,并制定一个目标;

Tread(Runnable target,String name):创建一个名为name的目标为target的线程;

Thread(ThreadGroup group,Runnable target):创建一个目标为target的,隶属于group线程组的线程;

通常我们可以讲一个类继承Thread类,然后覆盖Thread中的run()方法,这样就让这个类本身也就成了线程类了。

下面看一个用方式一实现的多线程的例子:

package day16;
public class TestMyThread {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
//      mt.run();
        mt.start();
        for(int i=1;i<101;i++){
            System.out.println("Main-----"+i);
        }
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=1;i<101;i++){
            System.out.println("run--------"+i);
        }      
    }
}
输出如下:
Main-----1
run--------1
Main-----2
run--------2
Main-----3
run--------3
Main-----4
run--------4
Main-----5
run--------5
Main-----6
run--------6
run--------7
Main-----7
run--------8
Main-----8
run--------9
......

   Main函数本身就是一个线程,在main中加入了一个线程,两个线程便会由cpu自行决定分配时间片,然后顺序执行,所谓的多线程并发执行其实也就是由cpu自行调度让程序串行化的执行,多线程的本质即把异步转化为同步,把并行转化为串行.

二:通过实现Runnable接口的方式来实现多线程

此接口中就一个run()方法,通过实现接口中的run()方法,来实现多线程的创建,使用这个接口时不能直接创建所需类的对象并运行它,而是必须从Thread类的一个实例内部运行它,比如这样:

package test;
public class TestMyRun {
    public static void main(String[] args) throws InterruptedException {
        MyRun mr = new MyRun();
        Thread t = new Thread(mr/*,"名字"*/);
        t.setName("乌龟");
        t.start();
        Thread.currentThread().setName("兔子!");
        for(int j=0;j<5;j++){
        System.out.println(Thread.currentThread().getName()+"--"+j);
        }
    }
}
class MyRun implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+"--"+i);
        }
    }
}
结果如下:
乌龟--0
兔子!--0
乌龟--1
兔子!--1
乌龟--2
兔子!--2
乌龟--3
兔子!--3
乌龟--4
兔子!--4

   以上两种方式的比较:

1. 使用Runnable接口

可以将CPU,代码和数据分开,形成清晰的模型;

还可以从其他类继承;

保持程序风格的一致性。

2.直接继承Thread

不能再从其他类继承;

编写简单,可以直接操作线程,无序是哟偶那个Thread.currentThread().

守护线程是个什么东西呢?记得以前在linux中听说个这个,那么在java中就本人所理解,守护线程不过就是一个特殊一点的线程,也可称之为后台线程它跟正常运行的线程有一些不同,可以说它是守护着这些普通线程的线程,可以这么说如果多线程运行着如果别的线程都结束了,那么守护线程也会稍稍迟一点点就结束,要是只有一个线程和守护线程同时运行着,那么当这个普通线程结束了,守护线程也就结束了,如果一个应用中只有后台线程在运行,JVM将推出该应用程序。

下面看一个守护进程的例子吧:

package day16;
public class TestDeamon {
    public static void main(String[] args) {
        Run1 r1 = new Run1();
        Thread th1 = new Thread(r1);
        th1.setPriority(10);
        th1.setDaemon(true);
        th1.start();
        for(int i=0;i<101;i++){
            System.out.println(i);
        }
    }
}
class Run1 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("我是守护线程!");
        }
    }
                         
}
结果如下:
……
93
94
95
96
97
98
99
100
我是守护线程!
我是守护线程!
我是守护线程!

   如去掉主方法中的for循环,那么输出结果为什么都不显示,即说明了上面的问题。

Thread类中多线程的使用中还有很多的方法即和线程控制有关的方法:

start():新建的线程进入Runnable状态;

run():线程进入Running状态;

notify()/notifyAll():唤醒其他的线程,这是一个独享方法,而不是线程方法;

wait():线程进入等待状态,等待被notify,这是一个对象方法,而不是线程方法;

Yield():让位,即线程放弃执行,使其他优先级不低于此线程的线程有机会运行,它是一个静态方法;

getPriority()/setPriority():获得/设置线程优先级;

Sleep():线程睡眠指定的一段时间;

Join():调用这个方法的主线程,会等待加入的子线程完成;

线程中过时的方法禁止使用,在其他类中的一些过时方法也不推荐使用。

看一下下面这个例子:

package test;
public class ThreadTestA {
  public static void main(String[] args) {
        Thread t1 = new MyThreadA();
        Thread t2 = new Thread(new MyRunnableA());
        t1.setName("Thread-01");
        t2.setName("Thread-02");
        t1.setPriority(10);
        t2.setPriority(10);
        t2.setDaemon(true);
        t1.start();
        t2.start();
        for(int i=1;i<5;i++){
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}
class MyThreadA extends Thread{
  @Override
    public void run() {
        for(int i=1;i<=5;i++){
            System.out.println(Thread.currentThread().getName()+": I = "+i);
        if(i%5==0){
            Thread.yield();
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        }
    }  
}
class MyRunnableA implements Runnable{
  @Override
    public void run() {
        char c = 'A';
        while(c<'Z'){
            System.out.println(Thread.currentThread().getName()+c);
            c++;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }  
    }
}
输出如下:
main1
Thread-02A
Thread-01: I = 1
main2
main3
main4
Thread-02B
Thread-01: I = 2
Thread-02C
Thread-01: I = 3
Thread-02D
Thread-01: I = 4
Thread-02E
Thread-01: I = 5
Thread-02F

   仔细的看一下Deamon进程的for循环还没结束,可是所有线程终止了,可见Deamon的特点了。