线程是什么
程序执行的基本单位就是线程
基础概念
Java内存模型
要研究Java内存模型必须得先知道JVM运行时数据区结构
顺序执行、并行、并发
- 顺序执行指一个步骤一个步骤的往下执行(只有前面的步骤完成了才能执行后面的步骤)。 如:我们要洗澡,那么就要先脱衣服->洗澡;而不能同时脱衣服和洗澡
- 并行执行指多个处理器同时执行(多个任务) 如:有多个人同时在洗澡
- 并发执行指一个处理器同时处理多个任务(严格意义来说是顺序执行的,但是由于处理器执行较快所以给人感觉是并行执行的) 如:我们去看电影。我们看到是动画效果的,实际上存储的是每一个帧。由于切换速度比人眼感知快,所以看到是动画
为什么使用多线程?
1.切记不要为了多线程而多线程。使用多线程会让代码的执行逻辑变得复杂,所以使用需谨慎。
2.线程不是越多越好,一定要根据实际业务特征,按需索取。且必须考虑CPU和IO资源的使用情况
- 合理的压榨CPU和内存资源
- 提高应用的吞吐量
- 降低应用的响应时间
多线程的评价标准是什么?
- 安全性 如何处理共享变量的问题,使得每次都能获取到预期值
- 生存性 无论发生什么该执行的逻辑都会被执行到(死锁)
- 能快速大量的执行处理
线程状态及其转化关系
如何创建多线程
- Thread
class PrimeThread extends Thread {
final private String name;
PrimeThread(String name) {
this.name = name;
}
public void run() {
System.out.println(name);
}
}
调用方式:
PrimeThread p = new PrimeThread("PrimeThread"); p.start();
- Runnable
class PrimeRun implements Runnable {
final private String name;
PrimeThread(String name) {
this.name = name;
}
public void run() {
System.out.println(name);
}
}
调用方式:
PrimeRun p = new PrimeRun(PrimeRun); new Thread(p).start();
- Callable
Callable是jdk1.5新增的功能。和Runnable功能类似,但是提供了调用返回值和检查性异常的功能
public class CallableTest implements Callable<String> {
final private String name;
public CallableTest(String name){
this.name = name;
}
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
final Future<String> future = Executors.newSingleThreadExecutor().submit(new CallableTest("CallableTest"));
final String threadName = future.get(3000, TimeUnit.SECONDS);
System.out.println(threadName);
final Future<String> lambdaFuture = Executors.newCachedThreadPool().submit(() -> "你好");
System.out.println(lambdaFuture.get(3000, TimeUnit.SECONDS));
}
@Override
public String call() throws Exception {
return name;
}
}
补充说明
Thread实现了Runnable接口并扩展了很多方法
多线程安全问题
多线程环境下,如果对临界(共享)资源进行并发的读写、写写就会导致线程安全问题
- volatile
volatile保证了线程的可见性,即每次读取临界资源的时候都从主内存中呼出和回写,而不会从本地内存(寄存器)中获取 - synchronized
synchronized是一种同步锁。只有获取到锁的线程才有可能执行。synchronized可以修饰代码块、方法、静态方法、类文件 如:Collections.SynchronizedSortedSet、StringBuffer - lock
读写锁,由于jdk1.5版本synchronized性能较低,所以产生了lock。但是jdk1.6之后对synchronized进行了优化。通过lock需要显性的获取锁和释放锁,而synchronized是jvm处理的
public final class SingletonLazy {
private static SingletonLazy singletonLazy;
private SingletonLazy(){}
public static SingletonLazy getInstance(){
if (null == singletonLazy){
ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock();
try {
if (lock.tryLock()){
if (null == singletonLazy){
singletonLazy = new SingletonLazy();
}
}
}finally {
lock.unlock();
}
// synchronized (SingletonLazy.class){
// if (null == singletonLazy){
// singletonLazy = new SingletonLazy();
// }
// }
}
return singletonLazy;
}
}
Java关于多线程的类(java.util.concurrent)
- Thread ThreadGroup
- Runnable
- Callable Future
- Lock ReadWriteLock ReentrantReadWriteLock
- ThreadFactory
- Executor Executors(工具类)
- Collections(集合类)
- ...
附录
维基关于线程的解释 zh.wikipedia.org/wiki/线程
维基关于线程安全 zh.wikipedia.org/wiki/线程安全
线程状态及其转化关系 blog.csdn.net/houbin0912/…
声明
引用该文档请注明出处