线程的同步
对于每个对象身上都有一把锁
它的状态不是1就是0
锁旗标
要让线程同步,只需要将多个线程拥有同一个锁旗标
synchronized(this){
aa();
}
0和1是同步的this ,2和3同步的是this
public synchronized void aa(){
}
public synchronized void bb(){
}
(JVM运行时数据区包含以下5个部分)
虚拟机的线程私有区间:
堆,方法区是属于线程共享区间
栈,本地方法栈,程序计数器属于线程独有的
线程的死锁
互相拿着对方的锁旗标,但是需要对方解锁
看图了解状态
线程状态JDK版(官方版):state
总共6种状态:NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED
Object对象有2个方法,
当被对象wait()时,进入等待状态
一个是wait()
一个是notifyAll()
suspend()与wait()的区别
suspend是线程的方法,实将当前线程挂起并且不会放对象的锁
wait()是对象的方法,但是实际是在操作改对象身上的线程,它调用后会放对象的锁
resume()与notify()的区别
==========================================
线程的同步
课堂案例:有2个线程,1个从1-->26,1个从A-Z
输出的效果是:1A2B3C....
输出的效果是:1AB2CD3EF4GH。。13YZ14ab。。。
生产者与消费者
线程间通讯(wait,notify)
产品最多积压10个,当数量达到10,我们就不能
生成,要等着消费
产品没有货为0个,我们就不能消费,要等着生产
生产者与消费者模式
生产者类 可被线程操作
消费者类 可被线程操作
产品类
对于多线程而言有原子性与可见性
锁的概念:
CAS原理(原子操作可以采用java.util.concurrent.atomic相关类)
Compare And Swap(比较交换技术)
自旋锁
悲观锁(synchronized)乐观锁(CAS):
公平锁/非公平锁(Synchronized):拿锁与申请顺序
独享锁/共享锁:是否多个线程共有(广义)
互斥/读写:狭义
可重入锁:是否需要再次申请锁
public synchronized void a(){
b();
}
public synchronized void b(){
}
synchronized优化:(jdk1.5之后)
无锁:CAS模式
偏向【心】锁:假设只有一个线程,第一次进入synchronized,会在对象头中记录线程的ID,以后进入直接比较发现一致,就进入
轻量锁:假设只有二个线程,当第一次进入synchronized锁住对象,那么另一个线程发生自旋(锁)
重量锁:就是一般情况
对于锁而言只有升级,没有降级
=============================================
线程的一些方法
yield与jion的区别
yield是当前线程抢到CPU,就让出CPU,重新抢
jion将交错运行的线程变成顺序执行的线程,
加入的线程执行完之后,再回头执行原来的线程
interrupt:通知线程改成中断状态
首先,一个线程不应该由其他线程来强制中断或停止,
而是应该由线程自己自行停止
Thread.stop, Thread.suspend, Thread.resume
都已经被废弃了
1.阻塞状态下直接抛出异常
2.运行状态下修改标志继续运行
锁:Lock----》ReentrantLock 的使用
ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition();
手动上锁:lock
手动解锁:unlock
类似wait方法:condition.await
类似notifyAll方法:condition.signalAll
可中断等待:trylock
ReentrantLock与synchronized区别
synchronized:非公平,悲观,独享,互斥,可重入
ReentrantLock:非公平(可改),悲观,独享,互斥,可重入
粒度
synchronized对于多条件上锁需要多次上锁(嵌套)
ReentrantLock对于多条件只要调用newCondition方法
synchronized对于并发不高的情况下性能优于ReentrantLock
并发高的情况下低于ReentrantLock
关于线程安全有3种
1.不安全
2.相对安全 Vector就是相对安全
3.绝对安全
volatile的作用
当一个线程修改变量的时候,是修改自己线程中的变量副本
其它线程对于该变量的修改是不可见的,volatile修饰的
变量属于全局内存共享,可以实时让其它线程可见
============================================
线程组:ThreadGroup(了解)
默认新建线程组属于创建它的线程所属的线程组
就是为了统一方便管理
ThreadGroup tg = new ThreadGroup(); tg.setPrority(10); tg.setDeamon(true); new Thread(tg).setDeamon(true);
一、多线程下载作业讲解
1.5
二、Callable的使用
FutureTask包装返回结果
三、什么是线程池,有什么作用?
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
创建一个定长线程池,支持定时及周期性任务执行。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
表示延迟3秒执行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
表示延迟1秒后每3秒执行一次
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
结果依次输出,相当于顺序执行各个任务
jdk1.7
ForkJoinPool pool = new ForkJoinPool();
打印0-300,小于50就输出,过大任务拆分
RecursiveAction:无返回:任务中只有fork,但是
主线程需要等待
pool.submit()
主线程等2秒
//pool.awaitTermination(2, TimeUnit.SECONDS);
数组求和
RecursiveTask:有返回:fork后还需要join
表示搜集分出做事情的结果
返回值为FutureTask



