Java 多线程

来源:互联网 发布:淘宝个人主页标签 编辑:程序博客网 时间:2024/06/11 02:34

Java 多线程

进程:是一个正在执行中的程序。
线程:执行路径或控制单元,是进程中的一个独立的控制单元,线程在控制着进程的进行。
一个进程中至少一个线程。

  java 虚拟机启动的时候会有一个进程,java.exe.该进程中至少有一个线程负责java 程序的执行,而且这个线程运行的代码运行在于main方法中,该线程成为主线程。
  
扩展:更细节说明jvm,jvm启动不止一个线程,至少还有个垃圾回收的线程。

意义:可以让我们在程序中多步代码同时运行。

进程或线程的创建真正意义上是有所依赖的系统创建的。

创建执行线程有两种方法:
一.将类声明为Thread类的子类,该子类应当重写Thread类的run方法.
步骤:
1. 定义类继承Thread
2. 复写Thread类中的run方法,目的是将自定义的代码存储在run方法中,让线程运行。
3. 调用线程的start方法,该方法有两个作用,第一,启动线程;第二调用run方法。

public class ThreadDemo {    public static void main(String[] args) {        Demo d = new Demo(); //创建好一个线程        d.start();        for (int i = 0; i < 100; i++) {            System.out.println("------");        }    }}class Demo extends Thread {    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println("*****");        }    }}

在ThreadDemo程序中:
这里写图片描述

我们会发现**和—-的打印并没有明确的先后顺序,每一次运行的结果都不同,因为多个线程都获取cpu的执行权,cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序运行。(多核除外),cpu在做着快速的切换,以达到看上去是同时运行的效果。此时有两条执行路径同时执行。其实并没有同时运行,只是系统对cpu进行快速的对这两个线程的调度。我们可以形象的把多线程的运行行为看做互相抢夺cpu的执行权。
这就是多线程的一个特点:随机性,谁抢到谁执行,至于执行多长,cpu说了算。

1.为什么要覆盖run方法?
  Thread 类用于描述线程,该类定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。

2.run方法和start方法的区别?

   public static void main(String[] args) {        Demo d = new Demo(); //创建好一个线程        //d.start(); //开启线程并执行该线程的run方法。        d.run();//仅仅是对象调用方法,而线程创建了,但并没有运行。        for (int i = 0; i < 100; i++) {            System.out.println("------");        }    }

练习:创建两个线程,和主线程交替运行.

public class ThreadDemo {    public static void main(String[] args) {        Text t1 = new Text("one");        Text t2 = new Text("two");        t1.start();        t2.start();        for (int i = 0; i < 1000; i++) {            System.out.println("------");        }    }}class Text extends Thread {    private  String name;    public Text(String name){        this.name=name;    }    public void run() {        for (int i = 0; i < 1000; i++) {            System.out.println(name+"*****");        }    }}

线程的五种状态:

这里写图片描述

自定义线程名称
每个线程都有它自己默认的名称。
Thread-编号,该编号从0开始。
getName();和setName();我们可以用线程的构造器构造线程的时候起名称。

public class ThreadDemo {    public static void main(String[] args) {        Text t1 = new Text("one");        Text t2 = new Text("two");        t1.start();        t2.start();        for (int i = 0; i < 1000; i++) {            System.out.println("------");        }    }}class Text extends Thread {    public Text(String name) {        super(name); //直接调用父类的构造方法    }  public void run() {        for (int i = 0; i < 1000; i++) {            System.out.println((Thread.currentThread()==this)+this.getName() + "*****");        }    }}

static Thread currentThread(); 获取当前的线程对象
getName():获取线程的名称

需求:简单的买票程序
多个窗口同时卖票。

/** * Created by Pitcher on 2017/9/25 0025 * Email:943990494@qq.com */public class TicketDemo {    public static void main(String[] args) {        Ticket t1=new Ticket();        Ticket t2=new Ticket();        Ticket t3=new Ticket();        Ticket t4=new Ticket();        t1.start();        t2.start();        t4.start();    }}class Ticket extends Thread{    private static int tick=100;    public void run(){        while (true){            if(tick>0){                System.out.println(currentThread().getName()+"....sale"+tick--);            }        }    }}

虽然这样可以实现,但是把票数定义为静态变量,生命周期太长了,因此我们看第二种创建线程的方式。

第二种方法
声明实现Runnable 接口的类,该类然后实现run方法。然后就可以分配该类的实例。
步骤:

  1. 定义类实现Runnable
  2. 覆盖Runnable接口中的方法,将线程要运行的代码放入run方法中
  3. 通过Thread类建立线程对象
  4. 将Runnable接口中的子类对象作为实际参数传递给Thread类的构造函数,
  5. 调用Thread的start方法开启线程,并调用Runnable子类的run方法
/** * Created by Pitcher on 2017/9/25 0025 * Email:943990494@qq.com */public class TicketDemo {    public static void main(String[] args) {        Ticket t=new Ticket();        Thread t1=new Thread(t);//创建了一个线程        Thread t2=new Thread(t);//创建了一个线程        Thread t3=new Thread(t);//创建了一个线程        Thread t4=new Thread(t);//创建了一个线程        t1.start();        t2.start();        t3.start();        t4.start();    }}class Ticket implements Runnable{    private  int tick=100;    public void run(){        while (true){            if(tick>0){                System.out.println(Thread.currentThread().getName()+"....sale"+tick--);            }        }    }}

为什么要实现Runnable 接口,因为Thread认识Runnable接口,我们在创建Thread的时候,将我们实现Runnable的对象传入其构造器中,就可以让该线程执行我们对象中的方法。

实现方式继承方式的区别?
实现方式的好处在于避免了单继承的局限性。在定义线程时,建议使用实现方式。
继承Thread:线程代码存放在Thread中,
实现Runnable:线程代码存放在子类的run方法中。

原创粉丝点击