线程脑图
多线程.pngThread相关
创建线程的方法:
1. 传Runnable方式。
2. Thread子类
3. 传FutureTask方式。
- Runnable方式:
Runnable方式没有返回值。
/**
* @author jtl
* @date 2019/10/11 17:03
* Thread常见的3种创建方式:Runnable
*/
public class ThreadDemo {
public static void main(String[] args) {
//Runnable
Thread threadA=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread is created with runnable");
}
},"ThreadA");
threadA.start();
}
}
- Thread子类的方式:
/**
* @author jtl
* @date 2019/10/11 17:03
* Thread常见的3种创建方式:Thread子类
*/
public class ThreadDemo {
public static void main(String[] args) {
ThreadC threadC=new ThreadC();
threadC.setName("ThreadC");
threadC.start();
}
private static class ThreadC extends Thread{
@Override
public void run() {
super.run();
System.out.println("ThreadC name is: "+getName());
}
}
}
- FutureTask方式:
FutureTask:有返回值。在执行futureTask.get()方法时。会阻塞当前线程,直到futureTask所在子线程执行完,才会唤醒当前线程。
/**
* @author jtl
* @date 2019/10/11 17:03
* Thread常见的3种创建方式: FutureTask
*/
public class ThreadDemo {
public static void main(String[] args) {
//FutureTask callable
Callable<String> callable=new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "Thread is created with callable";
}
};
FutureTask<String> futureTask=new FutureTask<>(callable);
Thread threadB=new Thread(futureTask,"ThreadB");
threadB.start();
try {
long tt=System.currentTimeMillis();
String msg=futureTask.get();
// 在执行futureTask.get() 会阻塞当先线程,直到子线程执行完毕,才会唤醒主线程
// 所以时间耗费为1000+ms
System.out.println(msg+"---" +(System.currentTimeMillis()-tt));
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
线程的生命周期:
1. 新建(New): 调用new方法,新建一个线程时,线程处于生命周期中的New。此时主要是为线程分配内存,初始化其成员变量。
2. 就绪(Runnable):调用start方法,启动一个线程。此时JVM完成了栈和程序计数器的创建,等待该线程的调度和运行。
3. 运行(Running):当处于Runnable的线程,被分配到CPU时间片后,线程开始执行run方法,此时处于运行状态。运行状态主要是执行run方法中的代码逻辑。
4. 阻塞(Blocked):运行中的线程,主动或者被动的放弃CPU的使用权暂停运行。线程调用Object.wait()方法(等待阻塞),没有竞争到锁而阻塞(同步阻塞),线程调用Thread.sleep(),Thread
.join()方法(其他阻塞)
5. 死亡(Dead):线程运行结束,或者因为异常退出。
线程的6种状态:
1. NEW:线程被创建还没有运行(start)时的状态。
2. RUNNABLE:线程在JAVA虚拟机运行时的状态。
3. BLOCKED:线程被阻塞,因为运行synchronized的同步方法时,没有竞争到锁而被阻塞时的状态。
4. WAITING:由于调用了Object.wait(),Thread.join(),LockSupport.park()等f非超时方法,导致线程处于等待状态,需要别的线程唤醒。
5. TIMED_WAITING:由于调用了Thread.sleep,Object.wait(long),Thread.join(long),LockSupport.parkNanos(),LockSupport.parkUntil()等方法时线程处于的状态。它和WAITING状态不同之处在于。它设置了超时等待的时间,而WAITING状态没有。
6. TERMINATED:线程已经退出时的状态。
/**
* A thread state. A thread can be in one of the following states:
* <ul>
* <li>{@link #NEW}<br>
* A thread that has not yet started is in this state.
* </li>
* <li>{@link #RUNNABLE}<br>
* A thread executing in the Java virtual machine is in this state.
* </li>
* <li>{@link #BLOCKED}<br>
* A thread that is blocked waiting for a monitor lock
* is in this state.
* </li>
* <li>{@link #WAITING}<br>
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
* </li>
* <li>{@link #TIMED_WAITING}<br>
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
* </li>
* <li>{@link #TERMINATED}<br>
* A thread that has exited is in this state.
* </li>
* </ul>
*
* <p>
* 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;
}
线程的常见方法
1. Thread.sleep():当前线程休眠,此时线程让出cpu,进入TIMED-WATING状态。如果该线程竞争到了锁,在执行该方法时不会释放锁。等睡眠时间过后,重新竞争cpu。
2. Thread.yield():让出CPU资源,和其他线程一起重新竞争CPU时间片。可能让出CPU之后,该线程会再次竞争到CPU。
3. Thread.holdLock(Object):传入一个Object对象,返回bool值。当前线程是否持有该对象锁。
4. join():当前执行该方法的线程进入WAITING状态。直到调用join方法的线程执行完毕或者别的线程调用interrupt方法报InterruptedException。Thread a = new Thread(); a.join();原理是调用了线程实例a的wait方法。需强调,a.join(5000)只是让调用该方法的线程进入TIMED_WAITING状态,一旦过了5秒之后,执行改方法的线程将继续往下执行。
5. setDaemon():设置该线程为守护线程。用户线程不全部退出,JVM不会退出。JVM退出,守护线程将死亡。
6. setPriority():设置该线程的优先级,优先级高的线程在分配CPU资源的时候更有可能被优先分配。线程优先级在 Thread.MIN_PRIORITY(1) ~ Thread.MAX_PRIORITY(10) 之间。1最低,10最高。
7. Thread.interrupted():返回某些线程是否已被中断。同时重置线程中断标记位。此时isInterrupted()返回为false。
8. isInterrupted():测试某些线程是否已被中断。
9. interrupt():当线程进入阻塞等待状态时,调用该方法会立刻报InterruptedException。退出BLOCKED或者WAITING状态。当线程为非阻塞状态,该方法会将Thread中的标志位设置为true,此时isInterrupted()返回为true。
/**
* Tests whether this thread has been interrupted. The <i>interrupted
* status</i> of the thread is unaffected by this method.
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if this thread has been interrupted;
* <code>false</code> otherwise.
* @see #interrupted()
* @revised 6.0
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests whether the current thread has been interrupted. The
* <i>interrupted status</i> of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
* <p>A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return <code>true</code> if the current thread has been interrupted;
* <code>false</code> otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
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();
}
sleep和wait方法的区别:
1. sleep()是Thread的方法,调用该方法后,当前线程休眠,此时线程让出cpu,进入TIMED-WATING状态。执行该方法时不会释放锁。
2. wait() 是Object的方法,调用该方法后,当前线程进入WAITING状态。此方法一般和synchronized一起使用,会释放锁。需要notify()/notifyAll()方法唤醒。
线程结束的几种方法:
1. 正常执行完逻辑代码。
2. 线程阻塞时,调用thread.interrupt方法,捕获InterrutedException异常。
3. 长时间循环运行的线程,用标记位来判断是否退出,具体看下方interrupt的示例代码
4. stop方法:此方法已被废弃,不建议使用
三个方法区别:isInterrupt(),interrupt(),Thread.interrupted()
1. isInterrupt():只返回当前线程是否中断的标记位。
2. Thread.interrupted():将标记位reset。此时再调用isInterrupt()返回的是false
3. interrupt():阻塞状态时:捕获InterruptException异常
非阻塞状态时:将当前线程标记位,设置为true。
----------------------------非阻塞情况下的三种代码测试----------------------------
/**
* @author jtl
* @date 2020/3/24 10:49
* 非阻塞情况下的三种代码测试
*/
class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
int count = 0;
//线程中断标记位为false。执行while循环
while (!Thread.currentThread().isInterrupted()) {
try {
if (count < 100) {
boolean a = Thread.currentThread().isInterrupted();
System.out.println("isInterrupted:" + a + " " + count++);
Thread.sleep(50);
} else if (count>=100 && count<200){
boolean a = Thread.currentThread().isInterrupted();//标记位为:false
Thread.currentThread().interrupt();//标记位设置为:true
boolean b = Thread.currentThread().isInterrupted();
Thread.interrupted();//标记位reset,此时标记位为:false。所以循环不会退出
boolean c = Thread.currentThread().isInterrupted();
System.out.println("isInterrupted:before:" + a + " isInterrupted:after:" + b + " isInterrupted:after:" + c + " " + count++);
}else{
boolean a = Thread.currentThread().isInterrupted();//标记位为:false
Thread.currentThread().interrupt();//标记位设置为:true。因为是非阻塞线程,所以不会捕获异常
boolean b = Thread.currentThread().isInterrupted();//标记位为:true
System.out.println("isInterrupted:before:" + a + " isInterrupted:after:" + b + " " + count++);
count = 0;
}
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("InterruptedException:"+ count + e.getMessage());
break;//退出循环
}
}
}
});
thread.start();
thread.join();//此处用join方法,wait住主线程,让主线程等待thread线程执行完毕
System.out.println("join:" + " interrupted:" + thread.isInterrupted());
}
}
----------------------------阻塞情况下的执行interrupt方法测试----------------------------
/**
* @author jtl
* @date 2020/3/24 10:49
* 阻塞情况下的执行interrupt方法测试
*/
class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("线程执行:sleep前");
//线程睡10秒
Thread.sleep(10000);
System.out.println("线程执行:sleep后");
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("线程异常:"+e.getMessage());
}
}
});
thread.start();
Thread.sleep(1000);
System.out.println("Thread标记位:"+thread.isInterrupted());//thread线程阻塞。此时标记位为默认的false
thread.interrupt();//thread线程阻塞。执行interrupt()方法捕获异常
System.out.println("Thread标记位:"+thread.isInterrupted());//thread线程。此时标记位为true
}
}
网友评论