线程创建的三种方式
创建线程的方式一:
- 1.创建:继承Thread,重写run方法
- 2.启动线程:创建子类对象,调用start方法。
创建线程的方式二:
(推荐方式)因为java是单继承的,所以一般不建议使用继承
- 实现Runnable接口,
- 创建实现类对象,创建代理类Thread对象。
创建方式三:继承Callable接口重写call方法。
public class TestThread extends Thread {
//线程的入口点。
@Override
public void run() {
for(int i=0;i<20;i++) {
System.out.println("一边听歌");
}
}
//主线程是在程序一启动就有了
public static void main(String[] args) {
// TODO Auto-generated method stub
//启动线程:创建子类对象,调用start方法。
TestThread st=new TestThread();
st.start();//start是开启一个线程,本身的代码会继续执行下去。
//start方法不会立即调用,是交给CPU去控制的
//注意线程创建的时机。
//st.run();//只是普通方法的调用。会将run执行完了才会继续执行
for(int i=0;i<20;i++) {
System.out.println("一边coding");
}
}
}
线程的状态:
新生状态:
Thread t=new Thread(),表示new一个线程,每个线程有自己的工作空间,从主内存拿取数据进行使用
就绪状态:
当调用start()方法时,线程立即进入就绪状态,但是并不意味着立即调度执行。只是具备运行的条件
- 在就绪队列中进行等待CPU的调度,
- 1.start
- 2.阻塞状态被接触时
- 3.yield方法
- 4.jvm本身将本地线程切换到其他的线程时。
运行状态:
就绪状态中的线程被CPU调度之后,才能进行运行状态,进入运行状态才能真正执行线程体的代码块
*
阻塞状态:
当调用sleep()(抱着资源睡觉),wait(站在旁边等着,不占用资源)或者同步所锁定时,线程进入阻塞状态,所谓的阻塞状态就是代码不往下执行,在等待着
- 同理不保证调用以上的方法就立即阻塞,阻塞事件解除后,重新进入就绪状态,等待CPU调度执行才能进入运行状态。
死亡状态:
正常死亡:即是代码执行完毕。或者强制中断执行。一旦进入死亡状态,不能再次调用start()方法。
线程的常用方法:
- isAlive():判断线程是否还活着
- currentThread():获得当前的线程
- setName():设置代理线程的名称
- getName():获得代理线程的名称
yield 礼让线程:表示线程从运行状态直接进入了就绪状态,让出CPU的调度,从新等待CPU的调度
- sleep是从运行状态进入了阻塞状态。
public class ThreadYield {
public static void main(String[] args) {
// TODO Auto-generated method stub
YieldThread my=new YieldThread();
new Thread(my,"a").start();
new Thread(my,"b").start();
}
}
class YieldThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"-->start");
Thread.yield();//当前的线程进行礼让
System.out.println(Thread.currentThread().getName()+"-->end");
}
}
终止线程
一般不推荐使用stop或者destroy方式强制终止线程的结束
一般是让程序自己执行完毕,或者是增加标识将其停止。
public class ThreadStop implements Runnable{
//1.加入标识,标记线程体是否可以运行
private boolean flag=true;
private String name;
@Override
public void run() {
// TODO Auto-generated method stub
//2.关联标识,true:线程体运行
//false:表示线程体停止
int i=0;
while(flag) {
System.out.println(name+"-->"+i++);
}
}
public ThreadStop(String name) {
super();
this.name = name;
}
//3.对外提供方法改变表示
public void terminate() {
this.flag=false;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadStop t=new ThreadStop("ab");
new Thread(t).start();
for(int i=0;i<99;i++) {
if(i==88) {
t.terminate();
System.out.println("t over");
}
System.out.println("main-->"+i);
}
}
}
阻塞状态:sleep是会占用资源休眠
- 利用模拟网络延时
- 或者进行倒计时。
- 1.模拟网络延时:放大了发生问题的可能性,就可以很清楚的认识到有些问题
- 2.进行倒计时处理。
public class ThreadSleep {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
int num=10;
while(true) {
Thread.sleep(1000);
System.out.println(num--);
if(num<0) {
break;
}
}
}
}
Join:合并线程待此线程执行完毕后才执行其他的线程。
public class ThreadJoin {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("爸爸让儿子买烟的故事");
new Thread(new Father()).start();
}
}
class Father extends Thread{
public void run() {
System.out.println("想抽烟,没烟了");
System.out.println("让儿子去买烟");
Thread t=new Thread(new Son());
t.start();
try {
t.join();//当前线程时Father,所以当运行到这里的时候,Father会被阻塞,等
//Son的进程完成之后才重调度执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("孩子一直没有回来");
}
System.out.println("老爸接过烟");
}
}
class Son extends Thread{
public void run() {
System.out.println("接过老爸的钱,出去买烟了");
System.out.println("发现路边有个游戏厅,进去玩了10分钟");
for(int i=1;i<=10;i++) {
System.out.println(i+"分钟过去了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("想起来买烟,赶紧买烟去");
System.out.println("手拿一包烟回家了");
}
}