Java 提供了三种创建线程的方法:
通过实现 Runnable 接口;
通过继承 Thread 类本身;
通过 Callable 和 Future 创建线程。
ThreadPoolExecutor extends ExecutorService extends Executor
ThreadPoolExecutor:线程池的具体实现类
newCachedThreadPoolExecutor:都是非核心线程,可以有无限数量的线程。60s回收空闲线程。
newFixedThreadPoolExecutor:固定线程数,都是核心线程,不回收空闲线程(核心线程)。
newScheduleThreadPoolExecutor:核心线程固定,非核心线程数无限。非核心线程空闲立即回收。
newSingleThreadExecutor
同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。
Thread.yield():会让运行中的线程切换到就绪状态(Runnable),重新争抢cpu的时间片,争抢时是否获取到时间片看cpu的分配。
yield:屈服;放弃
线程阻塞(Blocked)
线程的阻塞可以分为好多种,从操作系统层面和java层面阻塞的定义可能不同,
但是广义上使得线程阻塞的方式有下面几种
1、BIO阻塞,即使用了阻塞式的io流
2、Thread.sleep(long time):让线程休眠进入阻塞状态,该方法会抛出InterruptedException异常,即休眠过程中可被中断,被中断后抛出异常
3、mThread.join() 调用该方法的线程进入阻塞,等待mThread线程执行完恢复运行。
4、sychronized或ReentrantLock 造成线程未获得锁进入阻塞状态 (同步锁章节细说)
5、获得锁之后调用wait()方法 也会让线程进入阻塞状态 (同步锁章节细说)
6、LockSupport.park() 让线程进入阻塞状态 (同步锁章节细说)
Synchronized关键字:
1.对于静态方法,由于此时对象还未生成,所以只能采用类锁;Synchronized(XXX.class)
2.同一个类的不同对象的对象锁互不干扰。Synchronized(a)和Synchronized(b)互不干扰,并发运行临界区。
3.对象锁和类锁是独立的,互不干扰。
Synchronized:加锁
wait():释放锁,当前线程置入休眠状态,进入waitSet,可传入时间,如果指定时间内未被唤醒,则自动唤醒。wait()等同于wait(0),不会自动唤醒。
notify():不释放锁,随机唤醒一个waitSet里的线程.
notifyAll():不释放锁,唤醒waitSet中所有的线程.
重要:
- public static synchronized void method()和synchronized (A.class)锁住的都是类。
- public synchronized void method()和synchronized (this)锁住的都是对象。
- 同一个类锁/对象锁的多个方法,会被同一个线程锁住,其他线程无法访问这多个方法,但是可以访问未加锁的方法(没synchronized关键字的普通方法)。
- wait和notify使用场景是必须要有同步,synchronized,wait,notify,notifyAll必须使用同一个锁对象(this/XXX.class/某个对象的实例)。
wait 和 sleep的区别
- wait是Object的方法,sleep是Thread的方法
- wait()是用于线程间通信的,而sleep()是用于短时间暂停当前线程。
- wait后线程的状态是Watting,sleep后线程的状态为Time_Waiting
- Java中的wait方法应在同步代码块中调用,sleep则没要求。
- 进入wait状态的线程能够被notify和notifyAll线程唤醒,并且会释放实例对象所持有的锁。sleep不会被唤醒,也不会释放锁。
原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
可见性:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
有序性:即程序执行的顺序按照代码的先后顺序执行。
要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。
volatile
多线程的内存模型:main memory(主存)、working memory(线程栈),
在处理数据时,线程会把值从主存load到本地栈,完成操作后再save回去。
(volatile关键词的作用:每次针对该变量的操作都激发一次load and save)。
volatile一定程度上保证有序性(禁止指令重排序),不保证原子性。
volatile保证了可见性和有序性,volatile通过内存屏障来实现的。