Thread相关
###创建线程的方法:
- 传Runnable方式。
- Thread子类
- 传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();
}
}
}
线程的生命周期:
新建(New): 调用new方法,新建一个线程时,线程处于生命周期中的New。此时主要是为线程分配内存,初始化其成员变量。
就绪(Runnable):调用start方法,启动一个线程。此时JVM完成了栈和程序计数器的创建,等待该线程的调度和运行。
运行(Running):当处于Runnable的线程,被分配到CPU时间片后,线程开始执行run方法,此时处于运行状态。运行状态主要是执行run方法中的代码逻辑。
阻塞(Blocked):运行中的线程,主动或者被动的放弃CPU的使用权暂停运行。线程调用Object.wait()方法(等待阻塞),没有竞争到锁而阻塞(同步阻塞),线程调用Thread.sleep(),Thread
.join()方法(其他阻塞)死亡(Dead):线程运行结束,或者因为异常退出。
线程的6种状态:
NEW:线程被创建还没有运行(start)时的状态。
RUNNABLE:线程在JAVA虚拟机运行时的状态。
BLOCKED:线程被阻塞,因为运行synchronized的同步方法时,没有竞争到锁而被阻塞时的状态。
WAITING:由于调用了Object.wait(),Thread.join(),LockSupport.park()等f非超时方法,导致线程处于等待状态,需要别的线程唤醒。
TIMED_WAITING:由于调用了Thread.sleep,Object.wait(long),Thread.join(long),LockSupport.parkNanos(),LockSupport.parkUntil()等方法时线程处于的状态。它和WAITING状态不同之处在于。它设置了超时等待的时间,而WAITING状态没有。
TERMINATED:线程已经退出时的状态。
/**
A thread state. A thread can be in one of the following states:
- {@link #NEW}
A thread that has not yet started is in this state.
</li>
- {@link #RUNNABLE}
A thread executing in the Java virtual machine is in this state.
</li>
- {@link #BLOCKED}
A thread that is blocked waiting for a monitor lock
is in this state.
</li>
- {@link #WAITING}
A thread that is waiting indefinitely for another thread to
perform a particular action is in this state.
</li>
- {@link #TIMED_WAITING}
A thread that is waiting for another thread to perform an action
for up to a specified waiting time is in this state.
</li>
- {@link #TERMINATED}
A thread that has exited is in this state.
</li>
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:
- {@link Object#wait() Object.wait} with no timeout
- Thread state for a thread which has not yet started.
- {@link #join() Thread.join} with no timeout
- {@link LockSupport#park() 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.
*/
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:
- {@link #sleep Thread.sleep}
- {@link Object#wait(long) Object.wait} with timeout
- {@link #join(long) Thread.join} with timeout
- {@link LockSupport#parkNanos LockSupport.parkNanos}
- {@link LockSupport#parkUntil LockSupport.parkUntil}
- Thread state for a terminated thread.
- The thread has completed execution.
*/
TERMINATED;
/**
/**
}
线程的常见方法
Thread.sleep():当前线程休眠,此时线程让出cpu,进入TIMED-WATING状态。如果该线程竞争到了锁,在执行该方法时不会释放锁。等睡眠时间过后,重新竞争cpu。
Thread.yield():让出CPU资源,和其他线程一起重新竞争CPU时间片。可能让出CPU之后,该线程会再次竞争到CPU。
Thread.holdLock(Object):传入一个Object对象,返回bool值。当前线程是否持有该对象锁。
join():当前执行该方法的线程进入WAITING状态。直到调用join方法的线程执行完毕或者别的线程调用interrupt方法报InterruptedException。Thread a = new Thread(); a.join();原理是调用了线程实例a的wait方法。需强调,a.join(5000)只是让调用该方法的线程进入TIMED_WAITING状态,一旦过了5秒之后,执行改方法的线程将继续往下执行。
setDaemon():设置该线程为守护线程。用户线程不全部退出,JVM不会退出。JVM退出,守护线程将死亡。
setPriority():设置该线程的优先级,优先级高的线程在分配CPU资源的时候更有可能被优先分配。线程优先级在 Thread.MIN_PRIORITY(1) ~ Thread.MAX_PRIORITY(10) 之间。1最低,10最高。
Thread.interrupted():返回某些线程是否已被中断。同时重置线程中断标记位。此时isInterrupted()返回为false。
isInterrupted():测试某些线程是否已被中断。
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方法的区别:
- sleep()是Thread的方法,调用该方法后,当前线程休眠,此时线程让出cpu,进入TIMED-WATING状态。执行该方法时不会释放锁。
- wait() 是Object的方法,调用该方法后,当前线程进入WAITING状态。此方法一般和synchronized一起使用,会释放锁。需要notify()/notifyAll()方法唤醒。
线程结束的几种方法:
- 正常执行完逻辑代码。
- 线程阻塞时,调用thread.interrupt方法,捕获InterrutedException异常。
- 长时间循环运行的线程,用标记位来判断是否退出,具体看下方interrupt的示例代码
- stop方法:此方法已被废弃,不建议使用
三个方法区别:isInterrupt(),interrupt(),Thread.interrupted()
- isInterrupt():只返回当前线程是否中断的标记位。
- Thread.interrupted():将标记位reset。此时再调用isInterrupt()返回的是false
- 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
}
}