前言
简单了解在Java中的线程,以及如何创建并使用。其包括线程与进程的关系、在Java的Thread类中start与run方法的区别、在Java中线程的6种状态和转换方式、在Java中创建线程并使用的方式。
一、基本理解
1.什么是线程?
线程是进程中的一条执行路径,也是CPU的基本调度单位。一个进程至少要有一个线程(主线程),也可以有多个线程(可以创建子线程)。
2.线程与进程的区别
(1)进程是操作系统资源分配的基本单位,而线程是CPU的基本调度单位。
(2)一个运行中的应用至少有一个进程。
(3)一个进程至少要有一个线程(主线程),也可以有多个线程(可以创建子线程)。
3.在Java的Thread类中,start与run方法的区别
(1)start方法是启动一个新的线程的方法;
(2)run方法是在当前线程中执行的方法;
(3)当调用start方法时,会创建一个新的线程,并在新的线程中执行run方法;
(4)而直接调用run方法,会在当前线程中执行run方法,而不会创建新的线程;
4.Java中线程的6种状态(详情见源码:java/lang/Thread.java#state)
/**
* 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;
}
5.线程状态转换方式
(1)NEW -> RUNNABLE -> TERMINATED
import lombok.extern.slf4j.Slf4j;
import java.util.Timer;
import java.util.TimerTask;
@Slf4j
class DiyThread extends Thread {
public DiyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("HelloWorld!");
}
}
@Slf4j
public class Main {
public static void main(String[] args) {
DiyThread diyThread = new DiyThread("线程一");
log.info("1 - Thread:{} state:{}", diyThread.getName(), diyThread.getState()); // NEW
diyThread.start();
log.info("2 - Thread:{} state:{}", diyThread.getName(), diyThread.getState()); // RUNNABLE
// 启动后,先延时0秒,再每500毫秒执行一次任务
new Timer().schedule(new TimerTask() {
@Override
public void run() {
log.info("Thread:{} state:{}", diyThread.getName(), diyThread.getState());
}
}, 0, 500);
}
}
(2)NEW -> RUNNABLE -> TIMED_WAITING -> RUNNABLE -> TERMINATED
import lombok.extern.slf4j.Slf4j;
import java.util.Timer;
import java.util.TimerTask;
@Slf4j
class DiyThread extends Thread {
public DiyThread(String name) {
super(name);
}
@Override
public void run() {
try {
// 检查线程的中断状态
while (!interrupted()) {
Thread.sleep(1000);
}
} catch (InterruptedException interruptedException) {
System.out.println("捕获 InterruptedException 异常 => " + interruptedException);
} finally {
log.info("Thread:{} state:{}", Thread.currentThread().getName(), Thread.currentThread().getState());
}
}
}
@Slf4j
public class Main {
public static void main(String[] args) {
DiyThread diyThread = new DiyThread("线程一");
log.info("Thread:{} state:{}", diyThread.getName(), diyThread.getState()); // NEW
diyThread.start();
log.info("Thread:{} state:{}", diyThread.getName(), diyThread.getState()); // RUNNABLE
// 程序启动后,开始计算,第5秒后执行中断操作
new Timer().schedule(new TimerTask() {
public void run() {
/**
* 通知`线程一`执行中断操作
* 当一个线程调用 interrupt() 方法时,如果该线程正在执行可中断的方法(如:sleep、wait、join等),
* 那么它会立即受到一个 InterruptedException 异常,并且中断状态会被清除。这个异常可以让线程有机会
* 进行清理操作,然后终止线程的执行。
*/
diyThread.interrupt();
}
}, 5000);
// 启动后,先延时0秒,再每500毫秒执行一次任务
new Timer().schedule(new TimerTask() {
@Override
public void run() {
log.info("Thread:{} state:{}", diyThread.getName(), diyThread.getState());
}
}, 0, 500);
}
}
(3)NEW -> RUNNABLE -> BLOCKED -> TIMED_WAITING -> RUNNABLE -> TERMINATED
import lombok.extern.slf4j.Slf4j;
import java.util.Timer;
import java.util.TimerTask;;
@Slf4j
public class Main {
static Object money = new Object();
public static void main(String[] args) throws InterruptedException {
DiyThread diyThread = new DiyThread("线程一");
DiyThread diyThreadCopy = new DiyThread("线程二");
log.info("1 - Thread:{} state:{}", diyThread.getName(), diyThread.getState()); // NEW
log.info("1 - Thread:{} state:{}", diyThreadCopy.getName(), diyThreadCopy.getState()); // NEW
diyThread.start();
diyThreadCopy.start();
log.info("2 - Thread:{} state:{}", diyThread.getName(), diyThread.getState()); // RUNNABLE
log.info("2 - Thread:{} state:{}", diyThreadCopy.getName(), diyThreadCopy.getState()); // RUNNABLE
// 启动后,先延时0秒,再每500毫秒执行一次任务
new Timer().schedule(new TimerTask() {
@Override
public void run() {
log.info("Thread:{} state:{}", diyThread.getName(), diyThread.getState());
log.info("Thread:{} state:{}", diyThreadCopy.getName(), diyThreadCopy.getState());
}
}, 0, 500);
}
@Slf4j
static
class DiyThread extends Thread {
public DiyThread(String name) {
super(name);
}
@Override
public void run() {
synchronized (money) {
try {
System.out.println(Thread.currentThread().getName() + " -> 睡眠开始");
Thread.sleep(5000); // 线程一在5秒内都持有锁
System.out.println(Thread.currentThread().getName() + " -> 睡眠结束");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
log.info("Thread:{} state:{}", Thread.currentThread().getName(), Thread.currentThread().getState());
}
}
}
二、在Java中创建线程的方式
1.继承Thread方式
import lombok.extern.slf4j.Slf4j;
import java.util.Timer;
import java.util.TimerTask;
@Slf4j
class DiyThread extends Thread {
public DiyThread(String name) {
super(name);
}
@Override
public void run() {
int i = 0;
try {
while (!interrupted()) {
Thread.sleep(500);
log.info("Thread:{} state:{} run:{}", Thread.currentThread().getName(), Thread.currentThread().getState(), ++i);
}
} catch (InterruptedException e) {
log.info("Thread:{} state:{} run:{}", Thread.currentThread().getName(), Thread.currentThread().getState(), ++i);
e.printStackTrace();
}
}
}
@Slf4j
public class Main {
public static void main(String[] args) throws InterruptedException {
DiyThread diyThread1 = new DiyThread("线程一");
DiyThread diyThread2 = new DiyThread("线程二");
diyThread1.start();
diyThread2.start();
// 睡眠等待3秒
// Thread.sleep(3000);
// diyThread1.interrupt(); // 通知`线程一`执行中断操作
// log.info("3秒后,通知`线程一`执行中断操作");
// 延时等待3秒
new Timer().schedule(new TimerTask() {
public void run() {
diyThread1.interrupt(); // 通知`线程一`执行中断操作
log.info("3秒后,通知`线程一`执行中断操作");
}
}, 3000);
}
}
2.实现Runnable接口方式
import lombok.extern.slf4j.Slf4j;
@Slf4j
class DiyThread implements Runnable {
@Override
public void run() {
int i = 0;
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(500);
log.info("Thread:{} state:{} run:{}", Thread.currentThread().getName(), Thread.currentThread().getState(), ++i);
}
} catch (InterruptedException e) {
log.info("Thread:{} state:{} run:{}", Thread.currentThread().getName(), Thread.currentThread().getState(), ++i);
e.printStackTrace();
}
}
}
@Slf4j
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread diyThread1 = new Thread(new DiyThread());
Thread diyThread2 = new Thread(new DiyThread());
diyThread1.setName("线程一");
diyThread2.setName("线程二");
diyThread1.start();
diyThread2.start();
// 睡眠等待3秒
Thread.sleep(3000);
diyThread1.interrupt(); // 通知`线程一`执行中断操作
log.info("3秒后,通知`线程一`执行中断操作");
}
}
3.带返回值的线程方式
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
@Slf4j
class DiyCallable implements Callable<Integer> {
@Override
public Integer call() {
try {
Thread.sleep(2000);
log.info("Thread:{} state:{}", Thread.currentThread().getName(), Thread.currentThread().getState());
return 1;
} catch (Exception e) {
log.info("Thread:{} state:{}", Thread.currentThread().getName(), Thread.currentThread().getState());
return 0;
}
}
}
@Slf4j
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
DiyCallable diyCallable = new DiyCallable();
FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>) diyCallable);
Thread thread = new Thread(task);
thread.setName("带返回值的线程");
thread.start();
Integer res = task.get();
System.out.println(res);
}
}
4.定时器的线程
import lombok.extern.slf4j.Slf4j;
import java.util.Timer;
import java.util.TimerTask;
@Slf4j
public class Main {
public static void main(String[] args) {
Timer timer = new Timer();
// 启动后,先延时5秒,再每2秒执行一次任务
timer.schedule(new TimerTask() {
@Override
public void run() {
log.info("Thread:{} state:{}", Thread.currentThread().getName(), Thread.currentThread().getState());
}
}, 5000, 2000);
}
}
5.Lambda的线程使用方式
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class Main {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(50, 20, 30, 10, 40);
System.out.println(testStream(list));
System.out.println(testParallelStream(list));
}
private static int testStream(List<Integer> list) {
long startTime = System.currentTimeMillis();
list.stream().forEach(System.out::println);
long endTime = System.currentTimeMillis();
int sum = list.parallelStream().mapToInt(i -> i * 2).sum();
System.out.println("list.stream() -> 耗时:" + (endTime - startTime));
return sum;
}
private static int testParallelStream(List<Integer> list) {
// parallelStream的优势是:充分利用多线程,提高程序运行效率。
long startTime = System.currentTimeMillis();
list.parallelStream().forEach(System.out::println);
int sum = list.parallelStream().mapToInt(i -> i * 2).sum();
long endTime = System.currentTimeMillis();
System.out.println("list.parallelStream() -> 耗时:" + (endTime - startTime));
return sum;
}
}