多线程相关知识(浅)
1.三种方法创建线程
- 继承thread类
- 实现接口runnable
- 实现callable接口
2.三种方法的区别
- thread是个类只能继承一个,不推荐用
- runnable是个接口,一个类可以实现多个接口,推荐使用
- callable与runnable最大的区别在于它有返回值,runnable没有
3.实现同步的几种方式
- 基于jvm的同步机制
1.使用synchronized(可用于修饰于方法上,也可以单独用于代码块)
当线程想进入锁住的方法或代码块时,都需要获得该对象的锁,否则进入阻塞,每个对象只有一个锁,当运行完锁住的代码时,释放锁。
2.用voliate修饰变量
不同的线程修改变量,一般都是从内存中读取,复制一个模板,然后修改模板,经过一系列操作,最后再写到内存里。(这就会产生不同步的现象)。
凡是voliate修饰的变量,每次读取都是从共享内存中读取,每次修改变量的值,都会写到共享内存中(通俗的讲就是每次读到的都是最新的,每次修改都会第一时间更新数据)
3.wait,notify,notifyall和LockSupport里的park和unpark
wait,notify,notifyall必须用于synchronized加锁了的方法和代码里。他们都是object类的方法。wait会使当前线程进入阻塞,并释放该对象的锁,让其他线程获取锁对象,notify会唤醒监视在这个锁对象的随机一个线程,notifyall唤醒全部。这比LockSupport差了一些。
LockSupport里的park和unpark,是一种许可机制,park同样会使
线程阻塞,但park和unpark不一定要写在synchronized里面,unpark可以写在park前面,当遇到park阻塞立即放行,无论在park前面调用了多少次unpark,只能起效一次(比如前面用了3次unpark,后面代码执行到park,直接放行,然后又遇到park了,它就进入阻塞了)
4.sleep(睡眠时间),join方法
sleep()是thread内置的一个方法,里面的参数睡眠时间,单位毫秒,它会使线程进入阻塞,停在那等待一段时间再继续,就是偷懒睡了一会,它不会释放锁,其他线程都不能获得该对象的锁。
join也是thread的一个内置方法,当某个线程调用join()方法时,会江那个线程加入到当前线程,并等待它执行完,再继续执行当前线程。 - 基于jdk的同步机制
上面讲的是基于jvm的同步机制,一般要实现简单的同步用这个问题不大,但如果要用于复杂的同步,推荐使用java自己的ReentranntLock,jdk的锁比较灵活,可以自己设定是否是公平锁(公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。synchronized 中的锁是非公平的,ReentrantLock 默认情况下也是非公平的,但是也可以是公平的)。
1.lock和unlock
它需要自己手动加锁和手动释放锁。
2.signal,signalAll,await效果和使用基本等同于notify,notifyAll,wait(我感觉- -)
3.障碍器CyclicBarrier
障碍器我理解为调节线程之间的执行顺序。
CyclicBarrier cb = new CyclicBarrier(3,new MainTask());
new MyThread("A", cb).start();
new MyThread("B", cb).start();
new MyThread("C", cb).start();
//参数3就是有几个线程障碍,
// MyThread里面调用await方法的时候,
//告诉障碍器这个线程障碍已经完成了
//当这个三个障碍都解决了,则优先执行new MainTask()
4.线程池
好像有好几种线程池,有缓存池,单线程池,定长线程池等等,它们都是对ThreadPoolExcutor的实现,就是把里面的参数设定好了。不推荐直接使用这些定义好的,因为它们很多情况不符合实际,占用的内存太多。并且阿里的开发手册也强制规定不能用Excutors去创建(就是不能用现成的)。
new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue workQueue,RejectedExecutionHandler handler)
(1)corePoolSize: 核心线程(它们不会因超出空闲时间而被移除)
(2)maximumPoolSize: 线程池维护线程的最大数量
(3)keepAliveTime: 线程池维护线程所允许的空闲时间
(4)unit: 线程池维护线程所允许的空闲时间的单位
(5)workQueue: 线程池所使用的缓冲队列
(6)handler: 线程池对拒绝任务的处理策略
拒绝策略:就是就连缓冲队列里面的都装满了,还要加线程,只能拒绝了。
ThreadPoolExecutor.AbortPolicy:丢弃任务抛异常
ThreadPoolExecutor.DiscardPolicy:丢弃任务不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务