1.1 什么是线程
进程:系统进行资源分配的和调度的基本单位。
线程:CPU分配的基本单位。
程序计数器:一块内存区域,用来记录线程当前要执行的指令地址。
堆:主要存放使用new操作创建的对象实例。
方法区:用来存放JVM加载的类、常量及静态变量等信息。
1.2 线程的创建与运行
Java中有三种方式创建线程。
继承Thread类方式的实现:
public class ThreadTest {
// 继承Thread类并重写run方法
public static class MyThread extends Thread {
@Override
public void run() {
System.out.println("I am a child Thread");
}
}
public static void main(String[] args) {
// 创建线程
MyThread thread = new MyThread();
// 启动线程
thread.start();
}
}
好处:在run()方法中获取当前线程直接使用this就可以了,无需使用Thread.currentThread()方法。
不好:A.Java不支持多继承,如果继承了Thread类,就不能再继承其他类。
B.任务与代码没有分离,当多个线程执行一样的任务时需要多份任务代码。
Runnable接口的run方法实现:
public class ThreadTest {
public static class RunnableTask implements Runnable {
@Override
public void run() {
System.out.println("I am a child Thread implements Runnable");
}
}
public static void main(String[] args) {
RunnableTask task = new RunnableTask();
new Thread(task).start();
new Thread(task).start();
}
}
前两种方式都有一个缺点,就是任务没有返回值。
FutureTask的方式:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// 创建任务类,类似Runnable
public class CallerTask implements Callable<String> {
@Override
public String call() throws Exception {
return "hello";
}
public static void main(String[] args) {
// 创建异步任务
FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
// 启动线程
new Thread(futureTask).start();
try {
// 等待任务执行完毕,并返回结果
String result = futureTask.get();
System.out.println(result);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1.3 线程通知与等待
public class WaitNotifyTest {
// 创建资源
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() {
try {
// 获取resourceA共享资源的监视器锁
synchronized (resourceA) {
System.out.println("threadA get resourceA lock");
// 获取resourceB共享资源的监视器锁
synchronized (resourceB) {
System.out.println("threadA get resourceB lock");
// 线程A阻塞,并释放获取到的resourceA的锁
System.out.println("threadA release resourceA lock");
resourceA.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 创建线程
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
try {
// 休眠一秒
Thread.sleep(1000);
// 获取resourceA共享资源的监视器锁
synchronized (resourceA) {
System.out.println("threadB get resourceA lock");
System.out.println("threadB try get resourceB lock...");
// 获取resourceB共享资源的监视器锁
synchronized (resourceB) {
System.out.println("threadB get resourceB lock");
// 线程B阻塞,并释放获取到的resourceA的锁
System.out.println("threadB release resourceA lock");
resourceA.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 启动线程
threadA.start();
threadB.start();
// 等待两个线程结束
threadA.join();
threadB.join();
System.out.println("main over");
}
}
当线程调用共享对象时的wait()方法时,当前线程只会释放当前共享对象的锁,当前线程持有的其他共享对象的监视器并不会被释放。
notify()方法只会激活阻塞集合里面的一个线程。notifyAll()只会唤醒调用这个方法前调用了wait系列函数而被放入共享变量等待集合里面的线程。
public class WaitNotifyAllTest {
// 创建资源
private static volatile Object resourceA = new Object();
public static void main(String[] args) throws InterruptedException {
// 创建线程
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
// 获取resourceA共享资源的监视器锁
synchronized (resourceA) {
System.out.println("threadA get resourceA lock");
try {
System.out.println("threadA begin wait");
resourceA.wait();
System.out.println("threadA end wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 创建线程
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
System.out.println("threadB get resourceA lock");
try {
System.out.println("threadB begin wait");
resourceA.wait();
System.out.println("threadB end wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 创建线程
Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
System.out.println("threadC begin notify");
resourceA.notify();
}
}
});
// 启动线程
threadA.start();
threadB.start();
Thread.sleep(1000);
threadC.start();
// 等待线程结束
threadA.join();
threadB.join();
threadC.join();
System.out.println("main over");
}
}
1.6让出CPU执行权的yield方法
当一个线程调用yield方法时,当前线程会让出CPU使用权,然后处于就绪状态,线程调度器会从线程就绪队列里面获取一个线程优先级最高的线程,当然也有可能会调度到刚刚让出CPU的那个线程来获取CPU的执行权。
public class YieldTest implements Runnable {
YieldTest() {
// 创建并启动线程
Thread t = new Thread(this);
t.start();
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// 当i=0时让出CPU执行权,放弃时间片,进行下一轮调度
if ((i%5) == 0) {
System.out.println(Thread.currentThread() + "yield cpu...");
// 当前线程让出CPU执行权,放弃时间片,进行下一轮调度
Thread.yield();
}
}
System.out.println(Thread.currentThread() + " is over");
}
public static void main(String[] args) {
new YieldTest();
new YieldTest();
new YieldTest();
}
}
1.7 线程中断
public class SleepInterruptTest {
public static void main(String[] args) throws InterruptedException {
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("threadOne begin sleep for 2000 seconds");
Thread.sleep((2000000));
System.out.println("threadOne awaking");
} catch (InterruptedException e) {
System.out.println("threadOne is interrupted while sleeping");
return ;
}
System.out.println("threadOne-leaving normally");
}
});
// 启动线程
threadOne.start();
// 确保子线程进入休眠状态
Thread.sleep(1000);
// 打断子线程的休眠,让子线程从sleep函数返回
threadOne.interrupt();
// 等待子线程执行完毕
threadOne.join();
System.out.println("main thread is over");
}
}
1.9线程死锁
死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,在无外力作用的情况下,这些线程会一直相互等待而无法继续运行下去。
典型的死锁:
public class DeadLockTest {
// 创建资源
private static Object resourceA = new Object();
private static Object resourceB = new Object();
public static void main(String[] args) {
// 创建线程A
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
System.out.println(Thread.currentThread().getName() + " get resourceA");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " waiting get resourceB");
synchronized (resourceB) {
System.out.println(Thread.currentThread().getName() + " get resourceB");
}
}
}
},"Thread-A");
// 创建线程B
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceB) {
System.out.println(Thread.currentThread().getName() + " get resourceB");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " waiting get resourceA");
synchronized (resourceA) {
System.out.println(Thread.currentThread().getName() + " get resourceA");
}
}
}
},"Thread-B");
// 启动线程
threadA.start();
threadB.start();
}
}
1.11 ThreadLocal
public class ThreadLocalTest {
// (1) print函数
static void print(String str) {
// 1.1 打印当前线程本地内存中的localVariable变量的值
System.out.println(str + ":" + localVariable.get());
// 1.2 清除当前线程本地内存中的localVariable变量
localVariable.remove();
}
// (2) 创建ThreadLocal变量
static ThreadLocal<String> localVariable = new ThreadLocal<>();
public static void main(String[] args) {
// (3) 创建线程one
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
// 3.1 设置线程One中本地变量localVariable的值
localVariable.set("threadOne local variable");
// 3.2 调用打印函数
print("threadOne");
// 3.3 打印本地变量值
System.out.println("threadOne remove after" + ":" + localVariable.get());
}
});
// (4) 创建线程two
Thread threadTwo = new Thread(new Runnable() {
@Override
public void run() {
// 4.1 设置线程Two中本地变量localVariable的值
localVariable.set("threadTwo local variable");
// 4.2 调用打印函数
print("threadTwo");
// 4.3 打印本地变量值
System.out.println("threadTwo remove after" + ":" + localVariable.get());
}
});
// (5) 启动线程
threadOne.start();
threadTwo.start();
}
}
InheritableThreadLocal
public class TestThreadLocal {
// (1) 创建线程变量
public static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
// (2) 设置线程变量
threadLocal.set("hello world");
// (3) 启动子线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// (4) 子线程输出线程变量的值
System.out.println("thread:" + threadLocal.get());
}
});
thread.start();
// (5) 主线程输出线程变量的值
System.out.println("main:" + threadLocal.get());
}
}