
线程基础


创建线程的方式
1. 继承Thread类
继承Thread类、重写run方法、new 自定义的Thread的继承类、t.start启动线程。
注意是start启动而不是run启动。调用run就相当于调用一个普通的方法。
2. 实现Runnable接口
实现Runnable接口、重写run方法、创建Runnable实现类的实例myRunnable、创建Thread对象依赖myRunnable、t.start启动线程
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
t1.start();
t2.start();
3. 实现Callable接口
该方式可以接收线程的返回值。
实现Callable接口,有泛型规定返回值类型、重写call方法、创建MyCallable对象mc、创建FutureTask对象ft,用来接收返回值,同时需要依赖mc、创建Thread对象依赖ft、调用t.start启动线程、ft.get接收返回值
public class MyCallable implements Callable<String> { // 返回值类型是String
// 重写call方法,可以抛异常
}
// 开线程
MyCallable mc = new MyCallable();
FutureTask<String> ft = new FutureTask<String>(mc);
Thread t = new Thread(ft);
t.start();
String result = ft.get();
4. 创建线程池
后面详细讲解。
实现Runnable接口、重写run方法、创建线程池对象、submit方法提交任务、关闭线程池。


线程状态



保证线程按顺序执行

Notify和NotifyAll区别

唤醒的都是wait等待状态的线程。
wait和sleep区别







如何停止一个正在运行的线程?

- 退出标志

只打印了两次:

- Stop强制终止线程

- interrupted
打断阻塞(sleep)的线程


打断正常线程


调用interrupt方法修改了isInterrupted,从false变true,因此线程退出。
线程中的并发安全
sychronized底层原理
Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其它线程再想获取这个【对象锁】时就会阻塞住。
Object lock = new Object(); // 对象锁
// ...
public void test() {
sychronized(lock) {
// ...
}
}


Thread1释放了锁对象后,会唤醒EntryList中的所有线程,来争抢这个锁。注意:阻塞队列中是没有排队的,不是按照顺序发放锁。



重量级锁、轻量级锁、偏向锁、锁升级
Synchronized是重量级锁:jvm是系统级别,属于内核态,因此涉及用户态和内核态切换、进程上下文切换,成本高,性能低。
在JDK 1.6引入了两种新型锁机制:偏向锁和轻量级锁,它们的引入是为了解决在没有多线程竞争或基本没有竞争的场景下因使用传统锁机制带来的性能开销问题。
比如T1获得了锁,执行完了释放,后面还是他获得了这个锁,一个线程重复获得同一把锁!使用Synchronized性能低。


每个java 对象都可以关联一个 Monitor对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头Mark Word 中就被设置指向 Monitor 对象的指针。


释放锁时:锁记录=null表明这是一把重入锁,则直接-1,即删除这条Lock Record。锁记录≠null表明不是重入锁,则再来一次CAS交换地址。





一旦锁发生了竞争,都会升级为重量级锁!
JMM Java内存模型
注意不要混淆Java内存结构!


CAS







Volatile

- 线程可见性:用 volatile 修饰共享变量,能够防止编译器等优化发生,让一个线程对共享变量的修改对另一个线程可见。

- 防止指令重排:用 volatile 修饰共享变量会在读、写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果。





AQS







ReentrantLock

基本语法:




synchronized与lock的区别



一开始主线程获得了锁,T1也想要获得就会进入阻塞等待。调用了interrupt之后就会打断T1,不获得锁了。

tryLock获取锁失败之后会直接放弃!而不会阻塞等待。

可以通过参数设置等多长时间,如上是等待两秒钟。
多条件变量:可以唤醒锁。

ConcurrentHashMap






线程池
使用线程池:线程创建和销毁的开销都很大。







保证了执行顺序。

适合任务书密集,但执行时间都很短。


ThreadLocal







259

被折叠的 条评论
为什么被折叠?



