并发编程-线程

什么是线程?

同步与异步的理解
线程的各个状态的转变,如何判断线程是否死亡
用户线程和守护线程:通过setDaemon(true)来设置,必须再start前,运行中的用户线程无法设置为守护线程,守护线程不适合用在读写操作或者计算逻辑,因为JRE判断程序是否执行结束的标准是所有的前台执线程行完毕,而不管后台线程的状态,也就是说:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出
线程则是JVM级别,在Web 应用中启动一个线程,这个线程的生命周期并不会和Web应用程序保持同步,即使你停止了Web应用,这个线程依旧是活跃的
sychronized内置锁、lock显示锁
多线程和异步操作的异同


为什么用线程?
降低系统资源的消耗,线程属于稀缺资源,要节省着用
提高响应速率,任务进来了,不用去创建线程就可以直接调度执行
实现线程的统一管理(分配、调优、监管),无限制的创建线程,会降低系统的稳定性
(如果一个线程的运行时间非常长,就没必要使用线程池,)
使用下面五种方式的哪种方式好呢

 

怎么用线程?
创建:1.继承Thread类;2.实现Runnable接口;3.使用匿名内部类实现;3.callable;5.使用线程池创建线程
调用run(),只是使用实例调用方法
使用线程同步的时候,锁一定要是同一把锁
那么,哪个对象才是锁呢?
Java中的每一个对象都可以作为锁,而不同的场景锁是不一样的。
1.对于实例同步方法,锁是当前实例对象。
2.对于静态同步方法,锁是当前对象的Class对象。
3.对于同步方法块,锁是Synchonized括号里配置的对象。

非静态同步函数使用this对象、静态同步函数使用当前字节码文件对象(可以用 getClass方法获取,也可以用当前类名.class 表示)
导致死锁的原因:同步中嵌套同步
ThreadLocal为每个线程单独提供一个局部变量,线程间不相互影响
public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
  protected Integer initialValue() {
    return 0;
  };
};
volatile及时将修改的变量刷新到主内存中,效率高于synchronized,具有可见性但是无法保证数据原子性。禁止指令重排序优化,写操作相对普通稍慢(因为需要在本地代码段中插入许多内存屏障指令来保证处理器不发生乱序执行)
重排序:cpu会对没依赖关系的代码实现执行优化,在多线程情况下才会有影响

如何定义线程池核心线程数和总线程数的大小:CPU密集型(computer-bound)、IO密集型(I/O-bound)、混合密集型
算法:最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

实现Callable<V>接口,重写其call()方法,启一个线程执行里面的代码,最红得到结果放在V里,Future<v>接收结果并实现future模式处理结果,get()方法等
future模式:实例化控制类,控制类的get方法内设置一个由set方法控制的whilt循环,再新建一个线程在里面实例真正的计算类,并把计算类结果set进控制类;控制类接收结果并释放get类获取计算结果,最终返回出去
Executors.四种方式和new ThreadPoolExecutor()自定义;
重入锁(同一把锁,获得锁的线程在运行中还需重复调用加了锁的相应方法,会直接调用不会阻塞产生死锁,其他线程想要获取加了此锁的方法或代码,不行,反正就我行;一个线程持有某个管程对象上的锁,那么它就有权访问所有在该管程对象上同步的块。避免重入锁死:1.编写代码时避免再次获取已经持有的锁 2.使用可重入锁)、读写锁(分开读和写,即在写的情况下不能读也不能写,在读的情况下不能写但还能读,读读不加锁,读写不同行,在只有两个线程的情况下,读写锁相当于synchronized锁)、乐观锁(CAS无锁机制(原子类),先获取一个预期值version,在使用预期值去做操作,如果该预期值和实际值不一样,则断定为修改了,重试)、悲观锁(锁被占用就产生阻塞,一次一个)

生产消费:wait、notify,必须要在synchronized下进行执行,即持有同一把锁
wait和notify都放在Object里面,为了能使用任意对象进行加锁

分布式锁:zookeeper和redis

知识细节:java内存模型(属于jmm,多线程可见性);java内存结构(属于jvm,堆栈相关)

posted @ 2019-04-28 17:21  shuG214xin  阅读(126)  评论(0编辑  收藏  举报