线程与进程的区别

线程

  线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

  线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

    在Java Web中要注意,线程是JVM级别的,在不停止的情况下,跟JVM共同消亡,就是说如果一个Web服务启动了多个Web应用,某个Web应用启动了某个线 程,如果关闭这个Web应用,线程并不会关闭,因为JVM还在运行,所以别忘了设置Web应用关闭时停止线程。

线程对象是可以产生线程的对象。比如在Java平台中Thread对象,Runnable对象。线程,是指正在执行的一个指点令序列。在java平台上是指从一个线程对象的start()开始,运行run方法体中的那一段相对独立的过程。相比于多进程,多线程的优势有:

    (1)进程之间不能共享数据,线程可以;

    (2)系统创建进程需要为该进程重新分配系统资源,故创建线程代价比较小;

    (3)Java语言内置了多线程功能支持,简化了java多线程编程。

进程

  进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据在处理机上顺序执行时所发生的活动。操作系统中,几乎所有运行中的任务对应一条进程(Process)。一个程序进入内存运行,即变成一个进程。进程是处于运行过程中的程序,并且具有一定独立功能。描述进程的有一句话非常经典——进程是系统进行资源分配和调度的一个独立单位。

  进程是系统中独立存在的实体,拥有自己独立的资源,拥有自己私有的地址空间。进程的实质,就是程序在多道程序系统中的一次执行过程,它是动态产生,动态消亡的,具有自己的生命周期和各种不同的状态。进程具有并发性,它可以同其他进程一起并发执行,按各自独立的、不可预知的速度向前推进。 

(注意,并发性(concurrency)和并行性(parallel)是不同的。并行指的是同一时刻,多个指令在多台处理器上同时运行。并发指的是同一时刻只能有一条指令执行,但多个进程指令被被快速轮换执行,看起来就好像多个指令同时执行一样。)

  进程由程序、数据和进程控制块三部分组成。

Java多线程总结

一.创建线程与启动

1,继承Thread类创建,代码如下

2,定义一个继承Thread类的子类,并重写该类的run();方法

3,创建Thread子类的实例,即创建了线程对象

调用该线对象的start()方法启动线程。

public class DuoXianCheng extends  Thread{private  String name;public DuoXianCheng(){
    }public DuoXianCheng(String name){this.name=name;
    }//  创建线程和启动// 1通过继承Thread类创建线程类//  定义一个继承Thread类的子类,并重写该类的run()方法;//  创建Thread子类的实例,即创建了线程对象;//  调用该线程对象的start()方法启动线程。public void run(){for (int o=1;o<5; o++){
            System.out.println(name+"运行"+o);
        }
    }public static void main(String[] args) {
        DuoXianCheng duoXianCheng1 = new DuoXianCheng("A");
        DuoXianCheng duoXianCheng2 = new DuoXianCheng("B");//第三步启动线程        duoXianCheng1.start();
        duoXianCheng2.start();
    }
}

结果:(多次运行结果可能不一样)

Java多线程总结_多线程

二.实现Runnable接口创建线程类

定义一个Runnable的实现类,并重写该接口的run()方法;

创建Runnable实现类的实例,并以此实例作为Thread的target对象,

即该Thread对象才是真正的线程对像

通过实现Runnable接口创建线程类的具体步骤和具体代码如下:

public class SomeThreads implements Runnable {private  String name;public  SomeThreads(){
    }public SomeThreads(String name){this.name = name;
    }//   实现Runnable接口创建线程类//   通过实现Runnable接口创建线程类//  定义Runnable接口类的实现,并重写run()方法;//定义Runnable实现类的实例,并以此实例作为Thread的的target对象,即该Thread对象真正的线程对象    @Overridepublic void run() {for (int i=0;i<5;i++){
        System.out.println(name +"运行"+i);
    }
    }public static void main(String[] args) {
        SomeThreads someThreads1 = new SomeThreads("线程是s1");
        Thread thread1 = new Thread(someThreads1);
        SomeThreads someThreads2 = new SomeThreads("线程s2");
        Thread thread2 =new Thread(someThreads2);
        thread1.start();
        thread2.start();
    }

结果是:(每次运行的结果可能不一样)

Java多线程总结_多线程_02

创建多线程是选择实现Runnable接口还是继承Thread?

看Thread源码发现Thread也是实现Runnable接口的:

Java多线程总结_Java_03

 

Thread中的run方法调用的是Runnable接口的run方法,其实Thread和Runnable都实现了run方法,这种操作模式就是代理模式。

Thread和Runnable的区别

类继承Thread,则不适合资源共享。但是实现Runnable接口,就很容易实现资源共享。

public class Hello extends Thread{private  int count = 5;  //数量为5public  void run(){for (int i =0;i<6;i++){if (count>0){
                System.out.println(count--+"sount");
            }
        }
    }public static void main(String[] args) {
        Hello hello1 = new Hello();
        Hello hello2 = new Hello();
        hello1.start();
        hello2.start();
    }
}

运行结果:

Java多线程总结_Java_04

 可以看到,两个线程并没有进行资源共享,而是每个线程的count都等于5,接下来看

实现Runnable接口

 class World implements Runnable{private int count = 5; //剩余餐数为五    @Overridepublic void run() {for (int i =0;i<6;i++){if (this.count>0){
                System.out.println(Thread.currentThread().getName()+"剩余餐数"+this.count--);
            }
        }
    }
}public class sun{public static void main(String[] args) {
        World world1  = new World();new Thread(world1,"1号出餐口").start();new Thread(world1,"2号出餐口").start();

    }
}

运行结果:

Java多线程总结_多线程_05

 

 

 可以看出来,继承Thread没有进行资源共享,而实现Runnable进行了资源共享

总结一下二者:

实现Runnable接口比继承Thread类所具有的优势:

1.多个相同程序代码线程去处理同一个资源

2.可以避免Java中单继承的限制

3.增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

所以尽量使用实现Runnable接口

获取线程名字

public class Test01 implements Runnable{
    @Overridepublic void run() {for (int i =0;i<4;i++){
            System.out.println(Thread.currentThread().getName());
        }
    }public static void main(String[] args) {
        Test01 test01 = new Test01();new Thread(test01,"线程一的名字").start();new Thread(test01).start();
    }
}

结果:Java多线程总结_多线程_06 如果没有指定线程名字,Java会自动进行命名

 

 

另外要注意的是:mian方法也是一个线程。在Java中的线程是同时启动的,至于什么时候启动,那个先执行,完全看CPU的资源。

 

Java中,每次执行程序至少有两个线程启动。一个是main方法,一个是垃圾收集线程。因为每当使用Java命令执行一个类的时候。实际上都会启动JVM,每个JVM实际上就是在操作系统启动了一个进程。

如何判断线程是否启动

public class Start implements Runnable{
    @Overridepublic void run() {for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName());
        }
    }public static void main(String[] args) {
        Start start = new Start();
        Thread thread = new Thread(start);
        System.out.println("启动线程前"+thread.isAlive());
        thread.start();
        System.out.println("线程启动后"+thread.isAlive());
    }
}

结果:Java多线程总结_多线程_07

 

 

 

 主线程也有可能在子线程结束之前结束。并且子线程不受主线程结束而受到影响,子线程不会因为子线程结束而结束

线程的强制执行:

 class Test02 implements Runnable{
    @Overridepublic void run() {for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName());
        }
    }public static void main(String[] args) {
        Test02 error = new Test02();
        Thread thread = new Thread(error,"线程");
        thread.start();for (int i=0;i<50;i++){if (i>0){try {
                    thread.join(); //强制执行thread线程} catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("main方法强制执行线程-->" +i);
        }
    }
}

结果:Java多线程总结_Java_08执行多次结果可能不同

线程的休眠:

public class Test03Sleep implements Runnable{
    @Overridepublic void run() {for (int i=0;i<3;i++) {try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+i);
        }
    }public static void main(String[] args) {
        Test03Sleep test03Sleep = new Test03Sleep();
        Thread t = new Thread(test03Sleep,"线程");
        t.start();
    }
}

运行结果:(每隔一秒输出一个)

线程0

线程1

线程2

 

 

 线程的中断:

public class Duan implements Runnable{
    @Overridepublic void run() {
        System.out.println("执行run方法");try {
            Thread.sleep(10000);
            System.out.println("线程休眠完成");
        } catch (InterruptedException e) {
            System.out.println("线程休眠被中断");return;   //返回程序的调用处        }
        System.out.println("线程正常停止");
    }public static void main(String[] args) {
        Duan duan = new Duan();
        Thread thread = new Thread(duan,"线程");
        thread.start();try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt(); //3s后中断线程    }
}

结果:

执行run方法

线程休眠被中断

在java程序中,只要前台有一个线程在运行,整个java程序进程不会消失,所以此时可以设置一个后台线程,这样即使java进程消失了,此后台线程依然能够继续运行。

public class Hou implements Runnable{
    @Overridepublic void run() {while (true){
            System.out.println(Thread.currentThread().getName()+"运行中");
        }
    }public static void main(String[] args) {
        Hou hou = new Hou();
        Thread thread = new Thread(hou,"线程");
        thread.setDaemon(true);
        thread.start();
    }
}

虽然有个死循环,但是程序还是会终止的,因为死循环中的线程操作已经设置为后台运行。

线程的优先级:

public class You implements Runnable{
    @Overridepublic void run() {for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+"运行"+i);
        }
    }public static void main(String[] args) {
        Thread thread1=new Thread(new You(),"一");
        Thread thread2=new Thread(new You(),"二");
        Thread thread3=new Thread(new You(),"三");
        Thread thread4=new Thread(new You(),"四");
        thread1.setPriority(8);
        thread2.setPriority(5);
        thread3.setPriority(1);
        thread4.setPriority(6);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

线程不是优先级越高先执行。谁先执行取决于谁先去抢占CPU的资源,CPU的最高优先级是5

线程的礼让。

在线程操作中,也可以使用yield()方法,将一个线程的操作暂时交给其他线程执行。让CPU重新调度,但礼让不一定成功

public class Li implements Runnable{
    @Overridepublic void run() {for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+"运行"+i);if (i==3){
            System.out.println("执行礼让");
            Thread.yield();
        }
        }
    }public static void main(String[] args) {
        Thread thread1 = new Thread(new Li(),"一");
        Thread thread2 = new Thread(new Li(),"二");
        thread1.start();
        thread2.start();
    }
}

结果:

一运行0
二运行0
二运行1
一运行1
二运行2
一运行2
一运行3
执行礼让
二运行3
执行礼让
一运行4
二运行4