多线程简单基础
-
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
-
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
-
程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程的状态
/**
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,//新建
/**
* 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.
*/
RUNNABLE,//运行
/**
* 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
* {@link Object#wait() Object.wait}.
*/
BLOCKED,//阻塞
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
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:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,//具有指定时间的等待
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;//已终止线程的线程状态或线程已完成执行
}
线程的创建和调度
Thread
public class threadTest1 {
public static void main(String[] args) {
MyThread myThread = new MyThread();//线程创建
myThread.start();//启动线程
}
}
class MyThread extends Thread{
//重写Thread中run方法
//当线程启动的时候(start),就会运行run方法
@Override
public void run() {
System.out.println("线程创建和运行======>by extends Thread!");
}
}
Runnable
public class runnableTest1 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
}
class MyRunnable implements Runnable{
//实现run方法
@Override
public void run() {
System.out.println("线程创建和运行========>by implements Runnable!");
}
}
Callable
public class callableTest1 {
public static void main(String[] args) {
//开启异步任务
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
//启动线程
new Thread(futureTask).start();
try {
String res = futureTask.get();//通过get方法获取结果
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable {
//实现call方法
@Override
public String call() throws Exception {
return "线程创建和运行=======>by implements Callable!";
}
}
区别:
使用Thread集成的方式好处就是方便传参,可以在子类中添加成员变量,通过set方法设置或者构造函数进行传递,而Runnable方式,只能使用在主线程里面被声明为final的变量
但是Java是不支持多继承
但是Thread和Runnable都没有办法拿到任务的返回结果,但是Futuretask方式可以
线程中常用的方法
线程的通知notify和等待wait
wait():线程调用一个共享变量的wait()方法时,该调用线程会被阻塞挂起,直到满足下面的条件之一
public final void wait() throws InterruptedException {
wait(0);
}
- 其他线程调用了该共享对象的notify()或者notifyAll()
- 其他线程调用了该线程的interrupt()方法,该线程抛出Interruptedxception异常
public class threadTest3 {
static Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
Thread ThreadA = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("begin--------------");
//阻塞当前线程
synchronized (obj) {
obj.wait();
}
System.out.println("end---------------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
ThreadA.start();
ThreadA.sleep(1000);
System.out.println("begin interrupt threadA");
;
ThreadA.interrupt();
System.out.println("end interrupt threadA");
;
}
}
begin--------------
begin interrupt threadA
end interrupt threadA
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.scau.wjq.threadTest.threadTest3$1.run(threadTest3.java:16)
at java.lang.Thread.run(Thread.java:748)
Process finished with exit code 0
注意:如果调用wait()方法的线程没有事先获取该对象的监视器锁,调用wait的线程会抛出IllgalMonitorStateException异常
//当线程调用共享变量的wait()方法后只会释放当前共享变量的锁,如果当前线程还持有别的共享变量的锁,则这些锁是不会被释放的
public class threadTest2 {
private static volatile Object resourceA = new Object();
private static volatile Object resourceB = new Object();
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
System.out.println("threadA 获取 resourceA 锁");
//尝试获取resourceB资源共享监视器锁
synchronized (resourceB) {
System.out.println("threadA 获取 resourceB 锁");
//线程A阻塞,并释放获取取到了resourceA的锁
System.out.println("threadA 释放 resourceA 锁");
try {
resourceA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
synchronized (resourceA) {
System.out.println("threadB 获取 resourceA 锁");
//尝试获取resourceB资源共享监视器锁
synchronized (resourceB) {
System.out.println("threadB 获取 resourceB 锁");
//线程A阻塞,并释放获取取到了resourceA的锁
System.out.println("threadB 释放 resourceA 锁");
try {
resourceA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//启动线程
threadA.start();
threadB.start();
//等待两个线程结束
threadA.join();
threadB.join();
System.out.println("main线程结束");
}
}
threadA 获取 resourceA 锁
threadA 获取 resourceB 锁
threadA 释放 resourceA 锁
threadB 获取 resourceA 锁
Process finished with exit code -1
wait(long timeout):比wait()方法多了一个超时参数,如果一个线程调用共享对象的方法挂起后,没有在指定的timeout ms时间之内被其他线程调用该共享变量notify()或者notifyAll()方法唤醒,就会应为超时而放回。
//native方法
public final native void wait(long timeout) throws InterruptedException;
wait(long timeout, int nanos),只有在nanos>0的时候才能使timeout递增1
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
notify():唤醒一个在该共享变量上调用wait系列方法后被挂起的线程,一个共享变量上可能会有多个线程在等待,具体唤醒哪个等待的线程是随机的
注意被唤醒的线程不能马上从wait方法返回并继续执行,它必须在获取了共享对象的监视器锁后才可以返回,也就是说唤醒它的线程释放了共享变量上的监视器锁后,被唤醒的线程不一定会获取到共享对象的监视器锁,因为该线程还需要和其他线程一起竞争该锁,只有该线程竞争到了共享变量的监视器锁后才可以继续执行
public final native void notify();
notifyAll():唤醒所有在该共享变量上由于调用wait()系列方法而被挂起的线程
public final native void notifyAll();
等待线程执行终止join
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();//获取程序当前时间
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {//测试这个线程是否活着
wait(0);//时间为0阻塞线程
}
} else {
while (isAlive()) {//时间不为0就继续递归
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
//只有当999999>nanos>500000的时候才millis++
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);
}
//注意,假如线程A调用线程B的join方法后被阻塞,当其他线程调用了该线程的interrupt()方法中断了线程A时,线程A会抛出InterruptException异常
线程睡眠sleep
当一个执行中的线程调用了sleep方法,调用线程会暂时让出指定时间的执行权,也就是这期间不参与CPU的调度,但是该线程所拥有的的监视器资源,比如锁还是持有不让出的
//无论怎么执行,线程A在sleep的时间中,不会释放监视器资源,只有A执行完之后才能执行B
public class threadTest4 {
private static final Lock lock = new ReentrantLock();//独占锁
public static void main(String[] args) {
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("threadA sleep");
Thread.sleep(10000);
System.out.println("threadA awaked");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("threadB sleep");
Thread.sleep(10000);
System.out.println("threadAB awaked");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
});
threadA.start();
threadB.start();
}
}
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);
}
让出CPU执行权yield
当一个线程调用yield()方法时,实际上是在暗示线程调度器当前线程请求让出自己的CPU使用,但是线程调度器可以无条件忽略这个暗示
线程知识让出自己剩余的时间片,并没有被阻塞挂起,而是出于就绪状态,线程调度器下一次定都时就有可能调度到当前线程执行
public static native void yield();
public class threadTest5 {
public static void main(String[] args) {
new YieldTest();
new YieldTest();
new YieldTest();
}
}
class YieldTest implements Runnable {
YieldTest() {
Thread t = new Thread(this);
t.start();
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
if ((i % 5) == 0) {
System.out.println(Thread.currentThread() + "yield cpu...");
//当前线程让出CPU执行权,放弃时间片,进行下一轮调度
Thread.yield();
}
}
System.out.println(Thread.currentThread() + "is over");
}
}
Thread[Thread-0,5,main]yield cpu...
Thread[Thread-0,5,main]is over
Thread[Thread-2,5,main]yield cpu...
Thread[Thread-2,5,main]is over
Thread[Thread-1,5,main]yield cpu...
Thread[Thread-1,5,main]is over
//礼让后
Thread[Thread-0,5,main]yield cpu...
Thread[Thread-1,5,main]yield cpu...
Thread[Thread-2,5,main]yield cpu...
Thread[Thread-1,5,main]is over
Thread[Thread-2,5,main]is over
Thread[Thread-0,5,main]is over
线程中断interrupt
是一种线程间的协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是被中断的线程根据中断状态自行处理
//中断线程
//如,当线程A运行时,线程Bkeyi调用线程A的interrupt()方法来设置线程A的中断标志位true并立即返回。设置标志仅仅是设置标志,线程A实际并没有被中断,他会继续往下执行,如果线程A因为调用了wait,join,sleep等方法而被阻塞挂起,这时线程B调用A的interrupt(),线程A会抛出异常返回
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();
}
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
private native void interrupt0();
//检测当前线程是否被中断,是返回true
//和isInterrupted不同的是,如果发现当前线程被中断,则会清除中断标志,并且该方法是static,可以直接通过Thread类调用
public static boolean interrupted() {
return currentThread().isInterrupted(true);
//获取的是当前调用线程的中断标志而不是调用interrupted()方法的实例对象的中断标志
}
//检测当前线程是否被中断,是返回true
public boolean isInterrupted() {
//传递false,说明不清楚中断标志
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
public class threadTest6 {
public static void main(String[] args) throws InterruptedException {
Thread ThreadA = new Thread(new Runnable() {
@Override
public void run() {
for(;;){
}
}
});
ThreadA.start();
ThreadA.interrupt();//设置中断标志
/*
interrupted()是获取当前线程的中断状态
ThreadA.interrupted()和Thread.interrupted()作用一样,都是获取当前线程的中断标志
*/
System.out.println("isInterrupted "+ThreadA.isInterrupted());//true
System.out.println("isInterrupted "+ThreadA.interrupted());//false
System.out.println("isInterrupted "+Thread.interrupted());//false
System.out.println("isInterrupted "+ThreadA.isInterrupted());//true
ThreadA.join();
System.out.println("main thread is over");
}
}
public class thread7 {
public static void main(String[] args) throws InterruptedException {
Thread ThreadA = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().interrupted()){
}
System.out.println("threadA isInterrupted "+Thread.currentThread().isInterrupted());
}
});
ThreadA.start();
ThreadA.interrupt();//设置中断标志
ThreadA.join();
System.out.println("main thread is over");
}
}
threadA isInterrupted false
main thread is over
线程上下文
切换线程上下文时需要保存当前线程的执行现场,当再次执行时根据保存的执行现场信息回复执行现场
线程上下文切换时机:当前线程CPU时间片使用完处于就绪状态时,当前线程被其他线程中断时