通俗易懂理解java的多线程编程

文章类别 in java

在谈线程之前,先聊下进程!

进程:

是指正在运行的程序,是系统进行资源分配和调度的基本单位,是操作系统结构的基础,是操作系统动态执行的一个基本单位;

多进程:

当操作系统只有单进程的时候,那么它只能做一件事,而当它有了多进程后,那么它可以做多件事情,比如“同时” 听歌,上网…

线程:

就是进程的基本单位,线程是依赖于进程而存在的,在进程中可以执行多任务,而这些任务就是线程,线程是程序使用cpu的基本单位!

为什么使用java多线程?

因为,使用线程提高了cpu的使用率,提高了程序的执行速度!

java多线程的实现方式

一种是继承Thread重写run方法

public class ThreadDemo extends Thread {

        private int num = 5;
        @Override
        public void run() {
            while(num > 0)
            {
                System.out.println(this.getName()
                +"----"+num--);
            }
        }

}

//main
public class ThreadMain {

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        ThreadDemo td2 = new ThreadDemo();
        td.setName("thread one");
        td2.setName("thread two");
        td.start();
        td2.start();
    }

}

//输出:
thread one----5
thread two----5
thread one----4
thread two----4
thread one----3
thread one----2
thread two----3
thread one----1
thread two----2
thread two----1

一种是实现Runnable接口重写run方法

public class RunnableDemo implements Runnable {

    private int num = 5;

    @Override
    public void run() {
        while(num>0)
        {
            System.out.println(Thread.currentThread().getName() + "----"  +  num--);
        }
    }


}


//测试类:
public class MainDemo {

    public static void main(String[] args) {
        RunnableDemo rd = new RunnableDemo();
        Thread t = new Thread(rd);
        t.start();
    }

}
//输出结果:
runnable thread----5
runnable thread----4
runnable thread----3
runnable thread----2
runnable thread----1

大多数情况下都是用实现Runnable的方式来实现多线程的,Thread的类其实也是实现了Runnable接口,实现Runnable的方式来实现多线程的好处是解决了单继承的局限性,而且它还可以使用相同的代码去处理同一资源!

java的线程THREAD的安全问题

什么原因会导致线程的安全问题呢?

首先来看个例子:

在一个周末的晚上,哆啦A梦邀请了胖虎,小静,大雄去帮他卖铜锣烧,他们三位分别摆起了地摊,而这时候哆啦A梦拿出了30个铜锣烧希望他们一起卖完这30个!

分析:为了提高卖出铜锣烧的效率,那么就为他们三个人每人开启一个线程,这样就能很快的卖完了呀!

代码:

//定义一个线程类
public class SellTongLuoShao implements Runnable{

    private int num = 30;
    @Override
    public void run() {
        while(num>0)
        {
            try {
                Thread.sleep(300);//现实中没有说不休息就狂卖的!
                System.out.println(
                Thread.currentThread().getName()
                 + " 帮哆啦A梦卖出了第" + num--  + "个铜锣烧");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//main
public class MainDemo {

    public static void main(String[] args) {

        SellTongLuoShao luoShao = new SellTongLuoShao();
        Thread DaXiongThread = new Thread(luoShao);
        Thread XiaoJingThread = new Thread(luoShao);
        Thread PanHuThread = new Thread(luoShao);

        DaXiongThread.setName("大雄");
        XiaoJingThread.setName("小静");
        PanHuThread.setName("胖虎");

        DaXiongThread.start();
        XiaoJingThread.start();
        PanHuThread.start();


    }

}
//输出:
大雄 帮哆啦A梦卖出了第29个铜锣烧
小静 帮哆啦A梦卖出了第30个铜锣烧
胖虎 帮哆啦A梦卖出了第28个铜锣烧
小静 帮哆啦A梦卖出了第27个铜锣烧
大雄 帮哆啦A梦卖出了第27个铜锣烧
胖虎 帮哆啦A梦卖出了第26个铜锣烧
大雄 帮哆啦A梦卖出了第25个铜锣烧
小静 帮哆啦A梦卖出了第24个铜锣烧
胖虎 帮哆啦A梦卖出了第23个铜锣烧
大雄 帮哆啦A梦卖出了第22个铜锣烧
小静 帮哆啦A梦卖出了第21个铜锣烧
胖虎 帮哆啦A梦卖出了第20个铜锣烧
小静 帮哆啦A梦卖出了第19个铜锣烧
大雄 帮哆啦A梦卖出了第18个铜锣烧
胖虎 帮哆啦A梦卖出了第17个铜锣烧
小静 帮哆啦A梦卖出了第15个铜锣烧
大雄 帮哆啦A梦卖出了第16个铜锣烧
胖虎 帮哆啦A梦卖出了第14个铜锣烧
大雄 帮哆啦A梦卖出了第13个铜锣烧
小静 帮哆啦A梦卖出了第12个铜锣烧
胖虎 帮哆啦A梦卖出了第11个铜锣烧
小静 帮哆啦A梦卖出了第10个铜锣烧
大雄 帮哆啦A梦卖出了第9个铜锣烧
胖虎 帮哆啦A梦卖出了第8个铜锣烧
大雄 帮哆啦A梦卖出了第6个铜锣烧
小静 帮哆啦A梦卖出了第7个铜锣烧
胖虎 帮哆啦A梦卖出了第5个铜锣烧
小静 帮哆啦A梦卖出了第4个铜锣烧
大雄 帮哆啦A梦卖出了第3个铜锣烧
胖虎 帮哆啦A梦卖出了第2个铜锣烧
小静 帮哆啦A梦卖出了第1个铜锣烧
胖虎 帮哆啦A梦卖出了第0个铜锣烧
大雄 帮哆啦A梦卖出了第-1个铜锣烧

从输出结果可以看出,这是非常不符合逻辑的,不仅卖出了第0个,还有第负个,有些还是重复卖出,这并不是我们想要的结果,这样就导致了线程不安全,可是,这是为什么呢?

因为这段代码:

while(num>0) 
{ 
try { 
Thread.sleep(300);//现实中没有说不休息就狂卖的! 
System.out.println(Thread.currentThread().getName() + ” 帮哆啦A梦卖出了第” + num– + “个铜锣烧”); 
} catch (InterruptedException e) { 
e.printStackTrace(); 
} 
}

当大雄start了线程,开卖的时候,遇到了sleep方法,就在那里睡了300ms,如果这个时候,胖虎把最后一个铜锣烧给卖掉了,然后大雄醒来后,还继续执行接下来的代码! 这就导致了卖出第0个铜锣烧了!

如何解决呢?

java针对这种情况给我们配了一把锁!这把锁是来锁一个被共同操作的代码块,这样子,把:

try { 
Thread.sleep(300);//现实中没有说不休息就狂卖的! 
System.out.println(Thread.currentThread().getName() + ” 帮哆啦A梦卖出了第” + num– + “个铜锣烧”); 
} catch (InterruptedException e) { 
e.printStackTrace(); 
} 

这段代码给锁住之后,当大雄start后进来此run方法后,尽管他在里面睡了,但是别人也进不来,只有等大雄在run方法执行完,锁才会释放掉,这时候别人才能进来!这样就保证了线程的安全性!

那么。java线程锁长什么样呢?

长这样:

synchronized(对象){被锁住的代码}

将代码进行修复:

public class SellTongLuoShao implements Runnable{

    private int num = 30;
    @Override
    public void run() {
        while(num>0)
        {
            synchronized (new Object()) {//加锁
                try {
                    Thread.sleep(300);//现实中没有说不休息就狂卖的!
                    Thread.currentThread().getName() 
                    + " 帮哆啦A梦卖出了第" + num--  + "个铜锣烧");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

}

//main
public class MainDemo {

    public static void main(String[] args) {

        SellTongLuoShao luoShao = new SellTongLuoShao();
        Thread DaXiongThread = new Thread(luoShao);
        Thread XiaoJingThread = new Thread(luoShao);
        Thread PanHuThread = new Thread(luoShao);

        DaXiongThread.setName("大雄");
        XiaoJingThread.setName("小静");
        PanHuThread.setName("胖虎");

        DaXiongThread.start();
        XiaoJingThread.start();
        PanHuThread.start();


    }

}
//输出:
大雄 帮哆啦A梦卖出了第29个铜锣烧
胖虎 帮哆啦A梦卖出了第28个铜锣烧
小静 帮哆啦A梦卖出了第30个铜锣烧
大雄 帮哆啦A梦卖出了第26个铜锣烧
胖虎 帮哆啦A梦卖出了第25个铜锣烧
小静 帮哆啦A梦卖出了第27个铜锣烧
胖虎 帮哆啦A梦卖出了第24个铜锣烧
大雄 帮哆啦A梦卖出了第22个铜锣烧
小静 帮哆啦A梦卖出了第23个铜锣烧
大雄 帮哆啦A梦卖出了第21个铜锣烧
小静 帮哆啦A梦卖出了第19个铜锣烧
胖虎 帮哆啦A梦卖出了第20个铜锣烧
大雄 帮哆啦A梦卖出了第18个铜锣烧
小静 帮哆啦A梦卖出了第16个铜锣烧
胖虎 帮哆啦A梦卖出了第17个铜锣烧
小静 帮哆啦A梦卖出了第14个铜锣烧
大雄 帮哆啦A梦卖出了第13个铜锣烧
胖虎 帮哆啦A梦卖出了第15个铜锣烧
胖虎 帮哆啦A梦卖出了第11个铜锣烧
小静 帮哆啦A梦卖出了第10个铜锣烧
大雄 帮哆啦A梦卖出了第12个铜锣烧
大雄 帮哆啦A梦卖出了第9个铜锣烧
胖虎 帮哆啦A梦卖出了第7个铜锣烧
小静 帮哆啦A梦卖出了第8个铜锣烧
胖虎 帮哆啦A梦卖出了第6个铜锣烧
小静 帮哆啦A梦卖出了第5个铜锣烧
大雄 帮哆啦A梦卖出了第4个铜锣烧
大雄 帮哆啦A梦卖出了第3个铜锣烧
小静 帮哆啦A梦卖出了第1个铜锣烧
胖虎 帮哆啦A梦卖出了第2个铜锣烧

现在,就不会出现线程的安全性问题了!这也就是同步,虽然同步提高了线程的安全性,但是也降低了线程的运行效率!如果出现同步嵌套就容易会出现死锁问题!

除了这样的锁对象之外呢!还有一种是方法锁(同步方法),这种锁是在方法的修饰符后添加synchronized关键字!它的锁对象是this(当前对象!)

public class SellTongLuoShao implements Runnable{

    private int num = 30;

    @Override
    public synchronized void run() { //方法锁(同步方法)

        while(num>0)
        {
                try {

                    Thread.sleep(300);//现实中没有说不休息就狂卖的!
                    System.out.println(
                     + " 帮哆啦A梦卖出了第" + num--  + "个铜锣烧");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

        }
    }

}

如果这个方法是静态的话,那么锁对象就是class文件,也就是类名.class,不是静态的话就是this(当前对象!)

JDK5之后有了Lock锁,Lock锁和synchronized锁的主要区别是Lock锁可以在等待很长时间锁还没释放而自动放弃锁,synchronized锁是JVM层实现的,所以系统可以知道锁是什么时候释放的,而Lock锁是代码实现的,所以一般在代码的finally处添加unlock方法

public class SellTongLuoShao implements Runnable{

    private int num = 30;
    private Lock rLook = new ReentrantLock(); //创建锁对象
    @Override
    public void run() {

        rLook.lock();  //锁住
        try { 
            while(num>0)
            {
                try {
                    Thread.sleep(300);//现实中没有说不休息就狂卖的!
                    System.out.println(
                    " 帮哆啦A梦卖出了第" + num--  + "个铜锣烧");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
        finally
        {
            rLook.unlock(); //释放锁
        }

    }

}
//main
        public static void main(String[] args) {

        SellTongLuoShao luoShao = new SellTongLuoShao();
        Thread DaXiongThread = new Thread(luoShao);
        Thread XiaoJingThread = new Thread(luoShao);
        Thread PanHuThread = new Thread(luoShao);

        DaXiongThread.setName("大雄");
        XiaoJingThread.setName("小静");
        PanHuThread.setName("胖虎");

        DaXiongThread.start();
        XiaoJingThread.start();
        PanHuThread.start();


    }

}

这样也可以解决线程的安全性!

这里要注意一下线程的死锁问题!

java的线程死锁

出现死锁问题是因为对象在执行同步代码的时候,出现相互等待的情况

代码体现:

//创建两把锁
public class MyLock {

    public static Object obj1 = new Object();
    public static Object obj2 = new Object();

}



public class DeadLockDemo extends Thread{

    private boolean flag;
    public  DeadLockDemo(boolean flag) {

        this.flag = flag;
    }

    public void run() {
        while(true)
        {
            if(flag)
            {
                synchronized (MyLock.obj1) {
                System.out.println("if 语句, 用的是obj1的锁" );
                    synchronized (MyLock.obj2) {
                        System.out.println("if 语句,用的是obj2的锁");
                    }
                }
            }else
            {
                synchronized (MyLock.obj2) {
                    System.out.println("else 语句 用的是obj2的锁");
                    synchronized (MyLock.obj1) {
                        System.out.println("else 语句 用的是obj1的锁");
                    }
                }
            }
        }

    }


}
//main
public class MainDemo {

        public static void main(String[] args) {
            DeadLockDemo dd = new DeadLockDemo(true);
            DeadLockDemo dd2 = new DeadLockDemo(false);

            dd.start();
            dd2.start();
        }
}

//输出:
if 语句, 用的是obj1的锁
else 语句 用的是obj2的锁

这时候就出现死锁的情况,他们在互相等待!

线程是具有随机性的,那个线程先抢到cpu的执行权,那么它就会先执行!那么如果想要让一个线程先执行要咋办呢?

java的Join线程

使用join方法就可以优先执行这个线程! 比如:

public class SellTongLuoShao implements Runnable {

    private int num = 30;

    @Override
    public synchronized void run() {

            while (num > 0) {
                try {
                    Thread.sleep(300);// 现实中没有说不休息就狂卖的!
                    System.out.println(Thread.currentThread().getName()
                            + " 帮哆啦A梦卖出了第" + num-- + "个铜锣烧");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }

}

//main
    public static void main(String[] args) throws InterruptedException {

        SellTongLuoShao luoShao = new SellTongLuoShao();
        Thread DaXiongThread = new Thread(luoShao);
        Thread XiaoJingThread = new Thread(luoShao);
        Thread PanHuThread = new Thread(luoShao);

        DaXiongThread.setName("大雄");
        XiaoJingThread.setName("小静");
        PanHuThread.setName("胖虎");


        PanHuThread.start();
        PanHuThread.join();//join
        DaXiongThread.start();
        XiaoJingThread.start();


    }

}
//输出结果:
胖虎 帮哆啦A梦卖出了第30个铜锣烧
胖虎 帮哆啦A梦卖出了第29个铜锣烧
胖虎 帮哆啦A梦卖出了第28个铜锣烧
胖虎 帮哆啦A梦卖出了第27个铜锣烧
胖虎 帮哆啦A梦卖出了第26个铜锣烧
胖虎 帮哆啦A梦卖出了第25个铜锣烧
胖虎 帮哆啦A梦卖出了第24个铜锣烧
胖虎 帮哆啦A梦卖出了第23个铜锣烧
胖虎 帮哆啦A梦卖出了第22个铜锣烧
胖虎 帮哆啦A梦卖出了第21个铜锣烧
胖虎 帮哆啦A梦卖出了第20个铜锣烧
胖虎 帮哆啦A梦卖出了第19个铜锣烧
胖虎 帮哆啦A梦卖出了第18个铜锣烧
胖虎 帮哆啦A梦卖出了第17个铜锣烧
胖虎 帮哆啦A梦卖出了第16个铜锣烧
胖虎 帮哆啦A梦卖出了第15个铜锣烧
胖虎 帮哆啦A梦卖出了第14个铜锣烧
胖虎 帮哆啦A梦卖出了第13个铜锣烧
胖虎 帮哆啦A梦卖出了第12个铜锣烧
胖虎 帮哆啦A梦卖出了第11个铜锣烧
胖虎 帮哆啦A梦卖出了第10个铜锣烧
胖虎 帮哆啦A梦卖出了第9个铜锣烧
胖虎 帮哆啦A梦卖出了第8个铜锣烧
胖虎 帮哆啦A梦卖出了第7个铜锣烧
胖虎 帮哆啦A梦卖出了第6个铜锣烧
胖虎 帮哆啦A梦卖出了第5个铜锣烧
胖虎 帮哆啦A梦卖出了第4个铜锣烧
胖虎 帮哆啦A梦卖出了第3个铜锣烧
胖虎 帮哆啦A梦卖出了第2个铜锣烧
胖虎 帮哆啦A梦卖出了第1个铜锣烧

java中线程常常提到的就是守护线程,什么是守护线程呢?

java守护线程

就是当线程它成为了守护的时候,那么它就是肩负着守护的使命,当别的线程没了的时候,它也跟着没!!

public class SellTongLuoShao implements Runnable {

    private int num = 30;

    @Override
    public synchronized void run() {

            while (num > 0) {
                try {
                    Thread.sleep(300);// 现实中没有说不休息就狂卖的!
                    System.out.println(Thread.currentThread().getName()
                            + " 帮哆啦A梦卖出了第" + num-- + "个铜锣烧");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }

}
//main

public class MainDemo {

    public static void main(String[] args) throws InterruptedException {

        SellTongLuoShao luoShao = new SellTongLuoShao();
        Thread DaXiongThread = new Thread(luoShao);
        Thread XiaoJingThread = new Thread(luoShao);
        Thread PanHuThread = new Thread(luoShao);

        DaXiongThread.setName("大雄");
        XiaoJingThread.setName("小静");
        PanHuThread.setName("胖虎");
        //设置守护
        PanHuThread.setDaemon(true);
        DaXiongThread.setDaemon(true);
        XiaoJingThread.setDaemon(true);

        PanHuThread.start();
        DaXiongThread.start();
        XiaoJingThread.start();


        for(int i=0;i<4;i++)
        {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "----------------" + i);
        }


    }

}
//结果
胖虎 帮哆啦A梦卖出了第30个铜锣烧
胖虎 帮哆啦A梦卖出了第29个铜锣烧
胖虎 帮哆啦A梦卖出了第28个铜锣烧
main----------------0
胖虎 帮哆啦A梦卖出了第27个铜锣烧
胖虎 帮哆啦A梦卖出了第26个铜锣烧
胖虎 帮哆啦A梦卖出了第25个铜锣烧
main----------------1
胖虎 帮哆啦A梦卖出了第24个铜锣烧
胖虎 帮哆啦A梦卖出了第23个铜锣烧
胖虎 帮哆啦A梦卖出了第22个铜锣烧
main----------------2
胖虎 帮哆啦A梦卖出了第21个铜锣烧
胖虎 帮哆啦A梦卖出了第20个铜锣烧
胖虎 帮哆啦A梦卖出了第19个铜锣烧
胖虎 帮哆啦A梦卖出了第18个铜锣烧
main----------------3

可以看到,当主线程运行完毕之后,守护线程也跟着完毕

java多线程的等待唤醒机制

生产消费的问题:

比如哆啦A梦在生产铜锣烧,大雄在吃,而每当哆啦A梦生产一个,大雄就吃一个,哆啦A梦要先看有没有铜锣烧,有就等待,没有就生产一个(这时候就要用到同步),而大雄也是先看有没有铜锣烧,没有就等待,有就拿去吃(一样也需要用到同步!)。

这个时候如何保证他们可以如此进行下去不出错呢? 这时候哦就要用到等待唤醒机制了,分别是用到Object中的notify(唤醒)和wait(唤醒)方法!这两个方法的使用必须用锁对象来调用!

//铜锣烧类

public class TongLuoShao {

    private String tongluoshao  ;
    public boolean flag;//用来判断

    public String getTongluoshao() {
        return tongluoshao;
    }

    public void setTongluoshao(String tongluoshao) {
        this.tongluoshao = tongluoshao;
    }

}

//哆啦A梦
public class DuoLaAMeng implements Runnable{

    private TongLuoShao tongluoshao;
    private int x = 0;


    public DuoLaAMeng(TongLuoShao tongluoshao) {

        this.tongluoshao = tongluoshao;

    }



    @Override
    public void run() {

        synchronized (tongluoshao) {
            while(true)
            {
                //没有就生产,有就等待
                if(tongluoshao.flag)
                {
                    try {
                        tongluoshao.wait();//wait之后,锁就释放掉了!
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                if(x%2==0)
                {
                    tongluoshao.setTongluoshao("热腾腾的铜锣烧");
                }else
                {
                    tongluoshao.setTongluoshao("冰冻冻的铜锣烧");
                }
                x++;
                //修改标记
                tongluoshao.flag = true;
                //唤醒对方!(让大雄吃)
                tongluoshao.notify();
            }
        }

    }

}

//大雄
public class DaXiong implements Runnable {

    private TongLuoShao tongluoshao;

    public DaXiong(TongLuoShao tongluoshao) {
        this.tongluoshao = tongluoshao;
    }

    @Override
    public void run() {
        synchronized (tongluoshao) {
            //没有就等待,有就吃!
            while(true)
            {
                if(!tongluoshao.flag)
                {
                    try {
                        tongluoshao.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println("吃----" + tongluoshao.getTongluoshao());
                tongluoshao.flag = false;
				//唤醒对方!(让哆啦A梦生产)
                tongluoshao.notify();
            }
        }
    }

}

//main
public class MainDemo {

    public static void main(String[] args) {
        TongLuoShao tls = new TongLuoShao();

        DuoLaAMeng aMeng = new DuoLaAMeng(tls);
        DaXiong daXiong =  new DaXiong(tls);

        Thread t1 = new Thread(aMeng);
        Thread t2 = new Thread(daXiong);

        t1.start();
        t2.start();
    }

}

输出:
吃----热腾腾的铜锣烧
吃----冰冻冻的铜锣烧
吃----热腾腾的铜锣烧
吃----冰冻冻的铜锣烧
吃----热腾腾的铜锣烧
吃----冰冻冻的铜锣烧
吃----热腾腾的铜锣烧
吃----冰冻冻的铜锣烧
吃----热腾腾的铜锣烧
吃----冰冻冻的铜锣烧
吃----热腾腾的铜锣烧

java线程组

可以将线程列入到一个线程组里面,可以方便管理线程!

	DuoLaAMeng aMeng = new DuoLaAMeng(tls);
    DaXiong daXiong =  new DaXiong(tls);

    ThreadGroup tg = new ThreadGroup("team");

    Thread t1 = new Thread(tg,aMeng);
    Thread t2 = new Thread(tg,daXiong);

    tg.setDaemon(true);

将DaXiong 和 DuoLaAMeng 添加到线程组,那么操作线程组可以统一管理线程!如上就是把线程组中的线程设置为守护线程!

java线程池

线程池中的线程用完之后不会死亡!可以回收,等待下一个对象的使用!提高了性能! JDk5后有了Executors工厂类来产生线程池!

public class RunnableDemo implements Runnable{

    private int num = 10;

    @Override
    public void run() {

        while(num>0)
        {
            System.out.println(Thread.currentThread().getName() + "----------------" + num--);
        }

    }

}

//main
public class ExecutorDemo {

        public static void main(String[] args) {
            ExecutorService pool = Executors.newFixedThreadPool(2);
            pool.submit(new RunnableDemo());
            pool.submit(new RunnableDemo());

        }

}

java线程的第三种创建方式

借助线程池,使用到Callable接口

public class CallableDemo implements Callable<Integer> {


    private int num ;
    public CallableDemo(int num) {
        this.num  = num;
    }

    @Override
    public Integer call() throws Exception {

        num  = num + 90;

        return num;
    }


}

//main
public class MainDemo {

    public static void main(String[] args) {

        ExecutorService pool = Executors.newFixedThreadPool(2);
        Future<Integer> future = pool.submit(new CallableDemo(10));
        Future<Integer> future2 = pool.submit(new CallableDemo(100));

        try {
            System.out.println(future.get());
            System.out.println(future2.get());
        } catch (InterruptedException | ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

java线程的生命周期

新建—> 就绪 —> 运行 —>死亡!

新建:线程对象被创建出来; 就绪:线程被start后,进入就绪状态,此时具有执行的资格,但是还没有 执行的权利; 运行:线程有执行的资格和权利; 死亡:线程变成垃圾,等待被回收!

我的相关文章

相关资料