线程创建的两种方式
/**
* Description: <br>
*
* @author: name:yuxin <br>email: yuruixin@ixincheng.com <br>
* Create Time: 2018/3/10 0010-下午 5:30<br>
*/
public class MyThread1 extends Thread{
private int count=5;
private String name;
public MyThread1(String name){
this.name=name;
}
@Override
public void run(){
while (count>0){
System.out.println(name+"=卖出一张汽车票==剩余:"+count);
count--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* Description: <br>
*
* @author: name:yuxin <br>email: yuruixin@ixincheng.com <br>
* Create Time: 2018/3/10 0010-下午 5:40<br>
*/
public class MyThread2 implements Runnable{
private int count=5;
@Override
public void run() {
while (count>0){
System.out.println(Thread.currentThread().getName()+"=卖出一张火车票==剩余:"+count);
count--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类
/**
* Description: <br>
*
* @author: name:yuxin <br>email: yuruixin@ixincheng.com <br>
* Create Time: 2018/3/9 0009-下午 10:18<br>
*/
public class ThreadTest {
public static void main(String[] args) {
new MyThread1("窗口1").start();
new MyThread1("窗口2").start();
new MyThread1("窗口3").start();
MyThread2 myThread = new MyThread2();
Thread thread1 = new Thread(myThread,"窗口1");
Thread thread2 = new Thread(myThread,"窗口2");
Thread thread3 = new Thread(myThread,"窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
线程的生命周期
线程有五个状态,分别是新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)
新建
程序使用new会新建一个线程,new出的对象跟普通对象一样,JVM会为其分配内存,初始化成员变量等,此时线程并没有运行,而是就是新建状态。
就绪
当线程对象调用start后,线程将进入就绪状态。JVM会为其创建函数调度栈和计数器,但此时线程依然没有运行,而是等待获取CPU时间片。
线程何时会开始执行取决于CPU时间片的分配,由JVM调度器决定。
运行
当就绪状态的线程获取了CPU执行片的之后,就进入运行状态
阻塞
但是在执行过程中,可能会因为以下原因使线程进入阻塞状态:
1. CPU时间片已经用完,JVM切换到其他线程执行
2. 线程调用sleep()
3. 线程调用了阻塞IO方法,该方法返回之前,线程会一直阻塞
4. 线程试图获取被其他线程持有的同步监视器
5. 线程在等待某个通知
6. 程序调用了线程的suspend()将线程挂起。(容易死锁,不推荐)
线程从运行进入阻塞状态之后,接着只能继续阻塞或者再次进入就绪状态,下面情况会使线程由阻塞状态重新进入就绪状态:
1. 线程调用的sleep()经过了指定时间
2. 线程调用的阻塞IO方法返回
3. 线程成功获取同步监视器
4. 线程收到其他线程发出的通知
5. 被挂起(suspend)的线程又被程序调用了resume方法
线程死亡
线程结束后就处于死亡状态,线程会以如下三种方式结束:
1. run()或call()正常执行完成,线程正常结束
2. 线程抛出一个未捕获的Exception或Error
3. 直接调用线程的stop()方法结束线程,容易死锁
Java分为两种线程:用户线程和守护线程
所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
守护线程和用户线程的没啥本质的区别:唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。
将线程转换为守护线程可以通过调用Thread对象的setDaemon(true)方法来实现。在使用守护线程时需要注意一下几点:
(1) thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。
(2) 在Daemon线程中产生的新线程也是Daemon的。
(3) 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。