Java Concurrency

什么是进程

  • 进程是指可执行程序并存放在计算机存储器的一个指令序列,他是一个动态执行的过程

什么是线程

  • 线程是比进程还要小的运行单位,一个进程包含多个线程
  • 线程可以看做一个子程序

线程的创建

  • 创建一个Thread类,或者一个Thread子类的对象
  • 创建一个实现了Runnable接口的类的对象
  • 创建一个实现了Callable接口的类的对象

继承Thread类

1
2
3
4
5
public class CustomThread extends Thread {
public void run() {
System.out.println(getName() + " thread is running");
}
}

Runnable 接口

  • 只有一个方法run()
  • Runnable是Java中用已实现线程的接口
  • 任何实现线程功能的类都必须实现该接口
  • 为什么要实现runnable接口?
    • Java不支持多重继承,如果一个类已经继承了一个父类,那么他只能通过实现runnable接口变成线程
    • 可以不重写Thread类的其他方法,只需要重写Run()方法
1
2
3
4
5
6
7
8
9
10
public class PrintRunnable implements Runnable{
int i = 1;

@Override
public void run() {
while (i <= 10) {
System.out.println(Thread.currentThread().getName() + " is running " + (i++));
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class PrintRunnableTest {
@Test
public void testRunnableThread() {
PrintRunnable runnable1 = new PrintRunnable();

// use runnable object to create thread
// 2 threads are sharing the same variable
Thread t1 = new Thread(runnable1);
t1.start();

Thread t2 = new Thread(runnable1);
t2.start();
}

}

实现callable接口

  • 重写call()方法,作为线程的主体,具有返回值,并且可以对异常进行声明和抛出, 使用start()方法来启动线程
  1. 创建callable接口的实现类,并实现call()方法
  2. 创建callable实现类的实例,使用FutureTask类来包装callable对象,该FutureTask对象封装了callable对象的call()方法的返回值
  3. 使用FutureTask对象作为Thread对象的target,创建并启动线程
  4. 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
  • 实现callable接口,创建线程
1
2
3
4
5
6
7
public class CustomThread implements Callable<String> {
@Override
public String call() throws Exception {
String str = "thread message";
return str;
}
}
  • test thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Test
public void testCustomThread() {
Callable<String> callObj = new CustomThread();
FutureTask<String> ft = new FutureTask<>(callObj);
Thread thread = new Thread(ft);

// start thread
thread.start();

// the return value can only be got after thread has been started
try {
System.out.println(ft.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}

线程的状态

  1. new
  2. runnable
  3. running
  4. blocked
  5. dead

sleep方法的使用

  • public static void sleep(long millis)
  • 作用:在指定的毫秒数内让正在执行的线程休眠(暂停执行)
  • 参数为休眠的时间,单位是毫秒
1
2
3
4
5
6
7
8
while (i <= 30) {
System.out.println(Thread.currentThread().getName() + " is running " + (i++));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

join方法应用

  • public final void join()
  • 等待调用该方法的线程结束后才能执行 (调用者抢占CPU使用权)
  • public final void join(long millis)
  • 等待该线程终止的最长时间为millis毫秒

线程优先级

  • Java为线程类提供了10个优先级
  • 优先级可以用整数1-10表示,超过范围会抛出异常
  • 主线程默认优先级为5
  • getPriority()
  • setPriority()

优先级常量

  • MAX_PRIORITY 10
  • MIN_PRIORITY 1
  • NORM_PRIORITY 5 (默认)

多线程运行问题

  • 各个线程是通过竞争CPU时间获得运行机会的
  • 各线程什么时候得到CPU时间,占用多久,是不可预测的
  • 一个正在运行的线程在什么地方被暂停是不确定的

同步

  • synchronized 可以被用在
    • 成员方法
    • 静态方法
    • 语句块

线程间通信

  • 生产者 - 消费者 模型
  • wait()方法,终端方法的执行,是线程等待
  • notify()方法,唤醒处于等待的某一个线程,使其结束等待
  • notifyAll()方法,唤醒处于等待的所有线程,使它们结束等待