Java多线程的实现方式(3种)
创建方式:继承Thread类,实现runnable接口,实现Callable接口
1、继承Thread类:
hread 是一个类。Thread本身就实现了Runnable接口
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
MyThread myThread1 = new MyThread();
myThread1.start();
2、实现Runnable接口:
Runnable 是一个接口,该接口中只包含了一个run()方法
public class MyThread immplements Runnable {
public void run(){
sysout.out.println("MyThread.run()");
}
}
MyThread runThread = new MyThread();
Thread runThread = new Thread(runThread,"");
runThread.start();
3、实现Callable接口,通过FutureTask包装器创建Thread线程
/*
*Callable接口实际上是属于Executor框架中的功能类,
Callable接口与Runnable接口的功能类似,
但提供了比Runnable更加强大的功能。
*
*Callable可以在任务结束的时候提供一个返回值,
Runnable无法提供这个功能
*Callable的call方法分可以抛出异常,
而Runnable的run方法不能抛出异常。
/
class Tickets<Object> implements Callable<Object> {
//重写call方法
@Override
public Object call() throws Exception {
// TODO Auto-generated method stub
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
return null;
}
}
实现区别
1)、继承Thread类为单继承,实现Runnable方法为多实现,所以在灵活性上来说,使用实现Runnable方法更灵活;
2)、通过实现Runnable接口的方式可以实现多线程内的资源共享;
3)、增加代码的健壮性,代码可以被多个线程共享,代码和数据独立;
4)、线程池只能放实现Runnable或callable类的线程,不能直接放入继承Thread类的线程;
Runable接口和Thread类的区别主要包括以下几个方面
线程类继承自Thread则不能继承其他类(单继承)、而Runable接口可以
线程类继承自Thread相对于Runable来说,使用线程的方法更方便一些
实现Runnable接口的线程类的多个线程、可以更方便的访问同一个变量,而Thread类需要内部类来进行替换
Callable 和 Runnable接口的区别
Callable规定的方法是call(),而Runnable规定的方法是run().
Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
call()方法可抛出异常,而run()方法是不能抛出异常的。
运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。
它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
Callable是类似于Runnable的接口,
线程常用方法
start()
start():他的作用是启动一个新线程。start需要首先调用,start不能被重复调用,
run()
run(): run()就和普通的成员方法一样,可以被重复调用。
单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程!
yield()
yield()定义在Thread.java中,是Thread的静态方法
yield()的作用是让步。它能让当前正在执行的线程由“运行状态”进入到“就绪状态”,
从而让其它具有相同优先级的等待线程获取执行权;
但是,并不能保证在当前线程调用yield()之后,
其它具有相同优先级的线程就一定能获得执行权;
也有可能是当前线程又进入到“运行状态”继续运行!
sleep()
ssleep()定义在Thread.java中,是Thread的静态方法;
sleep方法的作用是让线程休眠指定时间,在时间到达时自动恢复线程的执行;
sleep方法不会释放线程锁;
在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行。
join()
join() 定义在Thread.java中。
join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行
使用方法:
在Father线程中调用:
sonThread.join();
则father线程会阻塞到son线程完成。
join的原理是用wait做的,因此其行为类似wait。
interrupt()o
Thread中的stop()和suspend()方法,由于固有的不安全性,已经建议不再使用!
interrupt()的作用是中断当前线程。
终止处于“阻塞状态”的线程
当线程由于被调用了sleep(), wait(), join()等方法而进入阻塞状态;
若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态,中断标记会被清除,
同时产生一个InterruptedException异常。将InterruptedException放在适当的位置就能终止线程
终止处于“运行状态”的线程
interrupt()并不会终止处于“运行状态”的线程!它会将线程的中断标记设为true
isDaemon() setDaemon()
守护线程
Java 中有两种线程:用户线程和守护线程。可以通过isDaemon()方法来区别它们:
如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。
用户线程一般用户执行用户级任务,而守护线程也就是“后台线程”,一般用来执行后台任务。
需要注意的是:Java虚拟机在“用户线程”都结束后会后退出。
setPriority() getPriority()
线程优先级、来指导JVM层面优先来执行那个成程序,
但最终的执行顺序需要操作系统来指定
java 中的线程优先级的范围是1~10,
最小值是1、默认的优先级是5。最大值是10
“高优先级线程”会优先于“低优先级线程”执行。
线程状态及状态转换
线程状态(5种)
public enum State {
NEW,新建状态 ->new Thread 给线程分配内存空间
RUNNABLE,执行状态
BLOCKED,阻塞状态
WAITING,等待状态:wait()线程进入wait状态
TIMED_WAITING,超时等待状态
TERMINATED;终止状态,线程执行完成的状态
}
JDK源码解读
NEW:
Thread state for a thread which has not yet started
RUNNABLE:
Thread state for a runnable thread. A thread in the runnable
state is executing in the Java virtual machine but it may
be waiting for other resources from the operating system such as processor
BLOCKED:
Thread state for a thread blocked waiting for a monitor lock
A thread in the blocked state is waiting for a monitor lock
to enter a synchronized block/method or reenter a synchronized block/method
after calling {Object.wait}
WAITING:
Thread state for a waiting thread.
A thread is in the waiting state due to calling one of the following methods:
1、{Object.wait} with no timeout
2、{Thread.join} with no timeout
3、{LockSupport.park}
A thread in the waiting state is waiting for another thread to perform a particular action
For example, a thread that has called Object.wait()
on an object is waiting for another thread to call
Object.notify() or Object.notifyAll() on that object.
A thread that has called Thread.join() is waiting for a specified thread to terminate.
TIMED_WAITING:
Thread state for a waiting thread with a specified waiting time
A thread is in the timed waiting state due to calling one of
the following methods with a specified positive waiting time:
1、{Thread.sleep}
2、{Object.wait} with timeout
3、{Thread.join} with timeout
4、{LockSupport.parkNanos}
5、{LockSupport.parkUntil}
TERMINATED:
Thread state for a terminated thread.
The thread has completed execution
新建状态(New)
用new语句创建的线程处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。
就绪状态(Runnable)
当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态,
Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权。
运行状态(Running)
处于这个状态的线程占用CPU,执行程序代码。只有处于就绪状态的线程才有机会转到运行状态。
阻塞状态(Blocked)
阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,
Java虚拟机不会给线程分配CPU。直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态可分为以下3种:
1、位于对象等待池中的阻塞状态(Blocked in object’s wait pool):
当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,
这涉及到“线程通信”的内容。
2、位于对象锁池中的阻塞状态(Blocked in object’s lock pool):当线程处于运行状态时,
试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,
Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。
3、其他阻塞状态(Otherwise Blocked):当前线程执行了sleep()方法,
或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。
死亡状态(Dead)
当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。