1 操作系统调度的最小任务单位是线程
2 创建进程的开销比创建线程大
3 进程间通信比线程间通信要慢
4 多进程比多线程的稳定性高,多进程中,一个进程崩溃不会影响其他进程,而在多线程情况下,任意个线程崩溃会导致整个进程崩溃
5 一个java程序实际上是一个JVM进程,JVM还有负责垃圾回收等其他工作线程
6 新线程执行指定代码的两种方法:
1 从Thread派生一个类,复写run()方法
2 创建Thread实例时,传入一个Runnable实例
7 通过对另一个线程对象调用join()方法可以等待其执行结束
8 线程共享变量要用Volatile关键字标记,确保每个变量都能读取到更新后的变量值
9 Java虚拟机中,变量的值保存在主内存中,线程访问变量时,会先获取一个副本,保存在自己的工作内存中,如果线程修改了变量,Java虚拟机会在不确定的时候在主内存中修改这个值
10 在X86架构下,JVM回写主内存的速度非常快
11 目标线程检测到isinterrupt()为True或者捕获了InterruptException之后应当立刻结束自身线程
12 守护线程
1 在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程
2 守护线程不能持有任何需要关闭的资源
13 临界区
1 加锁和解锁的代码块之间称为临界区
2 任何时候临界区最多只有一个线程执行
14 synchronized关键字对一个对象进行加锁
解决了多线程同步访问共享变量的正确性问题,但带来了性能下降。
15 单条原子操作的语句不需要同步,如果是多行语句,就必须保证是同步操作,因此可以使用技巧,将多行语句编程单条原子语句
16 String,Integer,Localdate,Math都是线程安全的
17 JVM允许同一个线程重复获取同一个锁,这种能被同一个线程重复获取的锁,叫做可重入锁
18 死锁一旦形成,只能强制结束进程
19 一个线程在this.wait()时,它会释放this锁
1 wait被释放的锁妖重新唤醒,需要在相同的锁上调用notify()方法
2 wait和notify用于多线程协调进行
3 notifyAll会唤醒所有当前正在this锁等待的进程
20 处理并发的包
java.util.concurrent
1 java.util.concurrent.locks提供的Reentrantlock用于替代synchronized加锁
2 在Reentrantlock中,condition中的await()和signal()、signalAll()来代替wait()和notify()
21 ReadWriteLock
1 只允许一个线程写入(其他线程不允许读也不允许写入)
2 没有写入时,多个线程同时读
22 StampedLock:新的读写锁
1 在读的过程中也允许获取写锁写入
2 StampedLock是不可重入锁,不能再一个线程中反复获取同一个锁
23 java.util.concurrent.atomic包中有原子操作的封装类
1 例如:AtomicInteger,其中incrementAndGet()表示加1后返回新值
2 通过无锁的方式实现线程安全,主要原理是利用:CAS
3 原子操作实现了无锁的线程安全
24 线程池
1 创建线程需要操作系统资源(线程资源,栈空间)
2 能接受大量小任务并进行分发处理的的就是线程池,线程池内部维护了若干个线程
3 ExecutorService接口表示线程池,接口的常用实现类有
FixedThreadPool:线程数固定的线程池
CeachThreadPool:线程数根据任务数动态调整的线程池
以上这些方法都被封装到Executors中