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()); } }