线程的创建方式
1.实现Runnable接口
java
public interface Runnable{
public abstract void run();
}
使用步骤:
1、创建一个Runnable接口的实现类,并实现run方法
2、实例化Runnable接口实现类
3、创建Thread类实例,将实例化的Runnable实例作为参数传递
4、启动子线程,调用Thread类的实例的start
public class Runabledeom implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"主线程运行");
}
}
//Runable 实现类的使用
Runabledeom runabledeom=new Runabledeom();
Thread thread = new Thread(runabledeom,"A");
thread.start();
System.out.println(Thread.currentThread().getName()+" ");
2.继承Thread
public class Thread implements Runnable
Thread类是Runnable接口的实现类,实现run方法
public void run(){
if(target !=null){
target.run();
}
}
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
使用步骤:
1.创建类,继承Thread(extends Thread),重写run方法
2.实例化当前创建的Thread的类的子类
3.启动子线程,调用start方法
3.实现Callable接口
public interface Callable<V> {
V call() throws Exception;
}
Callable接口提供了call方法,具有返回值,可以通过泛型来定义,该接口可以抛出异常
public interface Callable<V> {
V call() throws Exception;
}
public class FutureTask<V> implements RunnableFuture<V>
public interface FutureTask<V> extends Runable,Future<V>{
void run();
}
//实现Callable接口
CallableDemo callableDemo = new CallableDemo();
//通过FutureTask可以将Callable实现类兼容成Runable实现类
FutureTask futureTask = new FutureTask <>(callableDemo);
Thread thread = new Thread(futureTask);
thread.start();
使用步骤:
1.创建类,实现Callable接口,实现其提供的call方法
2.创建Callable实例
3.创建FutureTask实例,将Callable实例作为参数传入
4.创建Thread类实例,将FutureTask实例作为参数传入(当做Runnable实例)
5.调用start()方法
4.匿名类
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println();
}
});
thread1.start();
//在java8中通过lambda表达式
Thread thread2 = new Thread(() -> {
System.out.println();
});
Runnable接口与Callable接口区别:
1.Callable接口规定的方法是call()方法,Runnable 规定的方法是run()方法
2.返回值不同,Callable的任务执行后有返回值,Runnable无返回值
3.call方法可抛出异常,run()方法不能抛出异常
4.通过运行Callable的实例可以获取到FutureTask对象,FutureTask对象表示异步执行的结果,
他提供了我们的get()方法,可以异步获取线程的执行结果(get会阻塞当前线程。call方法的返回值可以通过FutureTask的实例提供的get方法类进行获取。
***FutureTask***知识扩展:
//get方法会阻塞当前线程的执行,直至当前线程执行结束,
// 当前线程获取到结果之后才能执行
Object o = futureTask.get();
//判断子线程是否被取消
futureTask.isCancelled();
//进行取消操作
futureTask.cancel(true);
System.out.println(o);
线程状态及其状态转换:
线程状态:
public enum state{
NEW,//新建状态
RUNNABLE;//就绪状态
BLOCKED,//阻塞状态
WAITING,//等待状态
TIMED_WAITING,//超时等待
TERMINATED;//终止状态
}
NEW:新建状态
用new创建的线程处于新建状态,此时和其他的java对象一样,仅仅在堆中分配了内存
RUNNABLE:就绪状态
当线程对象被创建后,一旦调用start方法,线程就处于就绪状态(其他的条件都满足),处于就绪状态的线程,
等待获取CPU的使用权。
RUNNING:运行状态
处于运行状态的线程也就占用了CPU,执行线程代码,只能从就绪状态到运行状态。
BLOCKED: 阻塞状态
阻塞状态的是指线程因为某些原因,放弃CPU(缺少资源:IO,锁),暂停停止运行,当前线程处于阻塞状态。
WAITING:等待状态
当线程处于该状态,如果某个线程中的对象调用wait(),jvm就会将线程放到等待池中。
TIMED_WAITING:超时等待
sleep(long time),join(long time)会使线程处于睡眠状态
TERMINATED(terminated):终止状态
当线程执行run()方法结尾时,就进入终止状态,表示线程的生命周期结束。
线常用方法介绍
线程生命周期:New,Runnable,Running,Terminate
线程需要相应资源时,进入阻塞状态,包含:Waiting,Blocked,Time_waiting状态
线程常用方法介绍
start():启动线程
启动一个新线程,start方法首先调用才能创建子线程,不能重复使用
public synchronized void start() {
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();//调用native方法
启动方法是需要底层OS来启动子线程,start是间接启动
JNI:java native interface,java 本地方法接口(JMM存在本地方法栈),调度系统本身提供的非java代码(c/c++)
run():整个子线程执行的业务逻辑都在run方法中,单独调用run方法,会在当前的线程中执行run操作,不会启动子线程,可重复调用。
public void run() {
if (target != null) {
target.run();
}
}
Thread类中的run方法知识判断任务体Runnable是否存在,
start() 和run()方法区别?
start()是启动子线程的,start()方法启动子线程后自动的来调动run()方法
run方法是子线程的业务执行体,不能直接调用run方法,通过调用run不能启动子线程的。
yield():线程让步
是用来暂停当前执行的线程,并且让步于其他相同优先级或更高优先级的线程先执行。就绪状态的线程会按照优先级进行调整。
yield:方法在thread中,是Thread类中的静态方法。
public static native void yield();
方法特点:
1.yield方法让步CPU资源,让给由系统决定,一般是让给相同优先级或者更高优先级的线程获得执行权,没有的话,会执行原来的线程。
2.yield让步:会让当前线程由“运行状态”到“就绪状态”。
3.yield让步CPU资源后,线程不会释放锁。
join():线程合并
暂停当前线程的执行,等待子线程的执行,也叫做线程合并,join方法是将并行执行的线程合并成串行执行。
eg:在线程ta中调用tb.join,会暂停ta的执行,先让tb执行完毕,ta才会执行
方法介绍:
t.join()//允许t线程在当前线程之前执行,待t线程执行结束当前线程在执行
t.join(long millis)(时间单位:毫秒)// 允许t线程在当前线程之前执行,且最长时间millis毫秒之后,当前线程才能执行
t.join(long millis,int nanos) // 提供秒级的精度
方法特点:
1.join方法是Thread类中的方法,会抛出InterruptedException中端异常
2.当前线程ta中tb.join,tb就会执行,ta线程会进入到WAITING或TIMED_WAITING状态
3.当前线程ta中tb.join,则ta线程会释放当前持有的锁,join方法实现是通过wait/notify线程通信方式来实现的,wait方法的使用会释放锁
Q:
join方法可以使线程进行顺序执行?假如存在A,B,C三个线程,让三个线程按照C、B、A的顺序执行???
//一直等待子线程
public final void join() throws InterruptedException {
join(0);
}
//提供毫秒,纳秒级别的等待时间
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
//纳秒的处理最终转换为毫秒
join(millis);
}
//提供毫秒级别的等待时间
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
//millis等于0,会一直判断子线程是否结束,否则会一直等待
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
//线程等待
wait(0);
}
} else {
//判断子线程是否结束且是否到达指定的毫秒数,否则会等待
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
Interrupt():中短线程
boolean isInterrupted():判断是否发生中断操作
用来中断当前线程,终止处于“阻塞状态”(WAITING/TIMED_WAITING)状态
方法介绍:interrupt():该方法在Thread类中,由对象操作方法
方法特点:
1.如果当前线程是可中断的阻塞状态(join,sleep,wait…会导致线程进入阻塞状态(WAITING/TIMED_WAITING)), 在任一的其他线程中调用interrupt()方法,会立即抛出 InterruptedException异常来停止阻塞状态。
2.如果当前是可运行状态,调用interruprt方法,线程会继续执行,直到发生了sleep等,进入阻塞状态后,随后抛出异常
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0();
}
private native void interrupt0();//JNI方法,终端操作由系统来提供
sleep():线程休眠
会让线程休眠,而且那个线程调用,那个线程休眠,TimeUtil.sleep(long),Thread.sleep
或当前的线程Thread.sleep,其结果都是线程休眠。
方法介绍:
sleep(long millis):
sleep(long millis, int nanos)
TimeUnit.DAYS(HOURS....).sleep(long timeout)
sleep()是Thread类提供的方法,会抛出异常InterruptedException。
特点:
1.sleep休眠期间,会让出CPU的使用权,但线程仍然有锁
2.sleep休闲时间到了之后,不会立即执行,而是线程由“阻塞状态”进入到“就绪状态”
public static native void sleep(long millis) throws InterruptedException;
public static void sleep(long millis, int nanos) throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
deamon:守护线程
方法介绍:
boolean isDaemon()//判断是否是守护线程
setDaemon(boolean on)//设置线程为守护线程,true:守护线程
java中的线程有两种:用户线程和守护线程
用户线程和守护线程是什么?
用户线程一般用户执行的用户级的线程.
守护线程也叫做后台线程,脱离于中端,用来服务于用户线程。eg:GC是一个单独的线程来处理,是一个守护线程
守护线程的生命周期?
依赖于用户线程,有用户线程存在,守护线程就会存活,无用户线程,守护线程也会消亡。
public final boolean isDaemon() {
return daemon;
}
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
Priority:线程的优先级
指导线程的执行优先级
方法:
int getPriority() //获取优先级
void setPriority(int newPriority) //设置优先级
特点:
1.优先级并不绝对,它所控制的是执行的机会,即优先级高的执行的效率比较大。
2.具有继承性,如果B在A中创建,B是A的子线程,两者具有相同的优先级
优先级范围:
public final static int MIN_PRIORITY = 1;//最小优先级
public final static int NORM_PRIORITY = 5;//默认优先级
public final static int MAX_PRIORITY = 10;//最大优先级
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
public final int getPriority() {
return priority;
}
线程调度(用户级调用和系统调用)
用户级调度
可以提供的调度方式:
1、调整线程优先级:Java线程有优先级,优先级高的线程获得较多的运行机会(运行时间);
static int Max_priority 线程可以具有的最高优先级,值为10;
static int MIN_PRIORIYT 线程可以具有的最低优先级,值为1;
static int NORM_PRIORITY 分配给线程的默认优先级,值为5;
Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级;
2、线程睡眠:Thread.sleep(long millins)使线程转到阻塞状态;
3、线程等待:Object.wait()方法,释放线程锁,使线程进入等待状态,
直到被其他线程唤醒(notify()和notifyAll());
4、线程让步:Thread.yeild()方法暂停当前正在执行的线程,使其进入等待执行状态,把执行机会让给相同优先级或更高优先级的线程,如果没有较高优先级或相同优先级的线程,该线程会继续执行;
5、线程加入:join()方法,在当前线程中调用另一个线程的join()方法, 则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再有阻塞状态转为就绪状态;
系统级调度
主要指系统在特定的时机自动进行调度,主要说明一下可运行状态到运行状态的调度,这个是OS的调度,主要涉及的调度算法
实时系统:
FIFO(First Input First Output,先进先出算法),
SJF(Shortest Job First,最短作业优先算法),
SRTF(Shortest Remaining Time First,最短剩余时间优先算法)。
交互式系统:
RR(Round Robin,时间片轮转算法),
HPF(Highest Priority First,最高优先级算法)。
基于时间片的优先级的调度算法