文章目录
1、创建线程的四种方式
(1)继承Thread类,重写run()方法
public class Rabbit extends Thread{
@Override
public void run() {
//线程体
for(int i=0;i<100;i++){
System.out.println("兔子跑了"+i+"步");
}
}
}
public class RabbitApp {
public static void main(String[] args) {
// 创建子类对象
Rabbit rab = new Rabbit();
// 对象.start()
rab.start();// 不要调用run()方法
}
}
(2)实现Runnable接口,实现run()方法
public class Programmer implements Runnable{
@Override
public void run() {
for(int i=0;i<67;i++)
{
System.out.println("一边敲helloWorld。。。。。");
}
}
}
/**
* * 创建线程:实现runnable接口+重写Run方法
* 启动多线程:使用静态代理
* (1)创建真实角色
* (2)创建代理角色+真实角色的引用
* (3)调用.start()
* @author Linlin Zhao
*
*/
public class ProgrammerApp {
public static void main(String[] args) {
//创建真实角色
Programmer pro=new Programmer();
//创建代理角色+真实角色的引用
Thread proxy=new Thread(pro);
//调用start
proxy.start();
for(int i=0;i<67;i++)
{
System.out.println("一边谈恋爱。。。。。");
}
}
}
(3)实现Callable接口,实现call()方法
/**
* Callable可以对外声明异常,同时可以返回值
* @author Linlin Zhao
*
*/
public class CallableCreate {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建线程
ExecutorService ser=Executors.newFixedThreadPool(2);
Race tortoise=new Race("乌龟",20);//小乌龟延时1000ms
Race rabbit=new Race("小兔子",50);//小兔子休息20000ms
//获取值
Future<Integer> result1=ser.submit(tortoise);
Future<Integer> result2=ser.submit(rabbit);
System.out.println("--------------");
Thread.sleep(10000);
tortoise.setFlag(false);
rabbit.setFlag(false);//停止线程循环
int num1=result1.get();
int num2=result2.get();
System.out.println("乌龟跑了----->"+num1+"步");
System.out.println("小兔子跑了----->"+num2+"步");
//停止服务
ser.shutdown();
}
}
class Race implements Callable<Integer>{
private String name;//名称
private long time;//延时时间
private boolean flag=true;
private int step=0;//步数
public Race(){
}
public Race(String name){
this.name=name;
}
public Race(String name, long time) {
super();
this.name = name;
this.time = time;
}
@Override
public Integer call() throws Exception {
while (flag){
Thread.sleep(time);//延时
step++;
}
return step;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
}
(4)使用线程池创建启动线程。
代码示例可见链接:
有关线程池的概念、四种创建方式、状态等问题
2、runnable和callable的区别
两者都是接口,都可以用来创建线程。Callable属于Executor框架中的类。Callable与Runnable接口的功能类似,区别主要在于以下几点:
(1)Callable可以在任务结束之后提供一个返回值。Runnable不可以。
(2)Callable中call()方法可以抛出异常。Runnable中的run()方法不可以。
(3)Callable运行过程中可以拿到一个Future对象,可以用来监视目标线程调用call()方法的情况。
3、线程有哪些状态?
线程有五种状态:新生状态、就绪状态、运行状态、阻塞状态、死亡状态。
(1)新生状态:(New)
创建一个线程对象之后,线程即进入新生状态。处于新生状态的线程有自己的内存空间,通过调用start()方法进入就绪状态(runnablle)。
(2)就绪状态:(Runnable)
线程进入就绪状态已经具备了运行条件,但是还没有分配CPU,所以处于就绪状态,等待系统分配CPU。一旦获得CPU,线程则进入运行状态(running)并调用自身的run()方法。
(3)运行状态:
运行状态的线程会执行自己的run()方法。直到因为原因堵塞或者完成任务而死亡。
(4)阻塞状态:
所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,进入阻塞状态。这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。等到阻塞的原因消除,线程就可以进入就绪状态,等待系统重新分配CPU从阻塞的位置开始继续运行。
引起阻塞的原因:调用了sleep()、join()、yield()等;等待获得IO等资源。
(5)死亡状态:
线程生命周期中的最后一个阶段。线程死亡的原因有两个:一个是完成任务正常死亡;另一个是调用了stop()或者destroy()方法强制终止线程,但是不建议使用着两种方法,前者会有异常,后者会强制终止,不会释放锁。