多线程入门总结

要更好的理解多线程的话,必须要把多线程的生命周期搞懂。

多线程的生命周期

1.新建(New):线程创建以后就处于新建状态,Thread t = new Thread();

2.就绪(Runnable):当线程调用start()方法就进入就绪状态,线程进入就绪状态后不会立即执行,而是会等待CPU来调用。

3.运行(Running):当CPU调用就绪的线程就进入运行状态了。

4.阻塞(Blocked):处于运行状态的线程由于某种原因,暂时放弃对CPU的使用权,此时进入阻塞状态,直到其进入就绪状态线程才能重新调用进入到运行状态。

根据阻塞原因的不同,阻塞状态可分为三种:

1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态。

2.同步阻塞:线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

5.死亡(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程的创建的常用两种方式

1.继承Thread类,重写该类的run()方法。

public class MyThread extends Thread {

    private String name;
    private static int num = 10000;

    public MyThread(String name) {
        this.name = name;
    }

    public void run() {
        for (int i = 1; i > 0; i++) {
            if(num>0){
                num = num-1;
            }else{
                break;
            }
            System.out.println("程序" + name + "在运行,当前num值"+num);
        }
    }


    public static void main(String[] args) {
        Thread thread1 = new MyThread("MyThread1");//新建线程MyThread,线程进入新建状态
        Thread thread2 = new MyThread("MyThread2");
        thread1.start();//线程调用start()进入就绪状态等待CPU调用
        thread2.start();
    }
}

 2.实现Runnable接口

public class MyRunnable implements Runnable {
    private String name;
    private static int num = 10000;

    public MyRunnable(String name) {
        this.name = name;
    }


    @Override
    public void run() {
        for (int i = 1; i > 0; i++) {
            if (num > 0) {
                num = num - 1;
                System.out.println("程序" + name + "在运行,当前num值" + num);
            } else {
                break;
            }
        }
    }

    public static void main(String[] args) {
        Runnable runnable1 = new MyRunnable("MyRunnable1");
        Runnable runnable2 = new MyRunnable("MyRunnable2");
        Thread thread1 = new Thread(runnable1); //新建线程MyRunnable1,线程进入新建状态
        Thread thread2 = new Thread(runnable2);
        thread1.start(); //调用start方法,进入就绪状态
        thread2.start();
    }
}

3.Thread和Runnable的区别

这里用最经典的买票举例

先贴代码吧

public class MyThread extends Thread {

    private int num = 5;
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    public void run() {
        try {
            for (int i = 1; i > 0; i++) {
                if (num > 0) {
                    num--;
                } else {
                    break;
                }
                sleep(100);
                System.out.println(name + "窗口,当前票数" + num);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        MyThread t1 = new MyThread("A");
        MyThread t2 = new MyThread("B");
        t1.start();
        t2.start();
    }
}

 用继承Thread方式运行结果可以看到车票被重复卖出了。再来看看实现Runnable接口的方式

public class MyRunnable implements Runnable {
    
    private int num = 5;

    @Override
    public void run() {
        for (int i = 1; i > 0; i++) {
            if (num > 0) {
                num--;
                System.out.println(Thread.currentThread().getName() + "窗口,当前票数" + num);
            } else {
                break;
            }
        }
    }

    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        new Thread(runnable, "A").start();
        new Thread(runnable, "B").start();
    }
}

 相信你已经可以看出区别了,但是多运行几次你会发现

 

 这是因为线程执行会出现抢占资源的情况导致不能同步,所以要加上synchronized关键字。

总结

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

(1):适合多个相同的程序代码的线程去处理同一个资源。

(2):可以避免java中的单继承的限制。

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

(4):你只要记住实际开发中一般都用实现Runnable的方式就完事了。

猜你喜欢

转载自www.cnblogs.com/caolyl/p/10184050.html