一:Thread是什么
线程Thread是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。 Java程序运行时,会启动一个JVM进程,JVM寻找到程序的入口main(),会创建一个主线程运行。一个java程序至少有一个进程,一个进程至少有一个线程。
二:线程的创建与使用
- 继承Thread,重写run方法
class MyThread extends Thread {
@Override
public void run() {
// do something
super.run();
}
}
MyThread myThread = new MyThread();
myThread.start();
复制代码
- 实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
// do something
}
}
Thread thread = new Thread(new MyRunnable());
thread.start();
复制代码
三:线程的状态
- 线程的状态标志
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
复制代码
- NEW 线程刚刚创建,尚未启动
- RUNNABLE 线程正在运行
- BLOCKED 线程堵塞状态,等待同步块的锁的释放,如果获得锁,就会自动进入运行状态
- WAITING 线程处于等待状态,需要被其他线程唤醒(notify、notifyAll方法的调用)。线程在调用了join之后,也会进入等待状态,直到被join的线程执行结束才会被唤醒
- TIMED_WAITING 有限时间的等待,一般出现在调用sleep(time),join(time),sleep(time)后
- TERMINATED 线程运行结束
- 线程的状态转换
四:线程的基本属性
private volatile String name; // 线程名称
private int priority; // 优先级,1~10
private boolean daemon = false; // 是否是守护线程
private Runnable target; // 实际被执行的对象
ThreadLocal.ThreadLocalMap threadLocals = null; // 当前线程的数据
private long tid; // 线程id
复制代码
五:线程创建初始化
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
// 获取当前线程,给新创建的线程设置线程组
Thread parent = currentThread();
if (g == null) {
g = parent.getThreadGroup();
}
// ThreadGroup nUnstartedThreads++;
g.addUnstarted();
this.group = g;
this.target = target;
this.priority = parent.getPriority(); // 使用父线程的优先级
this.daemon = parent.isDaemon(); // 使用父线程的属性,是否是守护线程
setName(name);
init2(parent);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
tid = nextThreadID();
}
复制代码
六:主要方法
public synchronized void start() {
// 判断状态,只能启动一次
if (threadStatus != 0 || started)
throw new IllegalThreadStateException();
group.add(this);
started = false;
try {
nativeCreate(this, stackSize, daemon);
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
// 执行方法,target是实际可执行的Runnable对象
public void run() {
if (target != null) {
target.run();
}
}
// 退出
private void exit() {
// 将当前线程冲ThreadGroup里面移除
if (group != null) {
group.threadTerminated(this);
group = null;
}
target = null;
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
// 线程中断
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
nativeInterrupt();
b.interrupt(this);
return;
}
}
nativeInterrupt();
}
public final void join(long millis) throws InterruptedException {
synchronized(lock) {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
lock.wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
lock.wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
}
public static native void yield();
复制代码
小结:
- 什么是守护线程?
守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出。(以上是针对正常退出,调用System.exit则必定会退出)
创建守护线程,thread.setDaemon(true);必须在start()之前调用。
参考:守护线程与普通线程
-
ThreadLocal
-
sleep
sleep使当前线程暂停,并没有释放锁,经过传入的time时间后自动继续执行。 -
yield
暂停当前线程,让其它优先级大于等于该线程的线程有机会先执行,不过不能保证该线程能够立即停止。 -
join
当前线程暂停,等待插入的线程执行完毕之后继续执行。 -
interrupt
线程中断,只是设置了一个中断标志,在线程中用户自己获取这个标志然后自己退出。