线程使用方式
4种方式模拟多线程,继承Thread、实现Runable接口、实现Callable接口、使用线程池。
class mytest4 extends Thread{
@Override
public void run() {
for (int i = 0; i <1000 ; i++) {
System.out.println("线程名字:"+Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
new mytest4().start();
new mytest4().start();
}
}
class b implements Runnable {
@Override
public void run() {
for (int i = 0; i <1000 ; i++) {
System.out.println("线程名字:"+Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
new Thread(new b(),"线程一").start();
new Thread(new b(),"线程二").start();
}
}
class c implements Callable{
public String arg;
public c(String arg) {
this.arg = arg;
}
@Override
public Object call() throws Exception {
for (int i = 0; i <1000 ; i++) {
System.out.println("线程名字:"+Thread.currentThread().getName()+":"+i+"参数"+arg);
}
return "自定义返回值";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> c = new c("juno");
FutureTask<String> futureTask=new FutureTask<>(c);
new Thread(futureTask).start();
System.out.println("获取多线程的返回值:"+futureTask.get());
}
public static void main(String[] args) {
//带缓存的线程池
Executors.newCachedThreadPool();
//特定长度的线程池
Executors.newFixedThreadPool(5);
//有执行周期的线程池
Executors.newScheduledThreadPool(1);
//单个线程的线程池
Executors.newSingleThreadExecutor();
}
}
线程安全问题
保证原子性,可见性,指令不重排即可保证线程安全。
原子性: 一系列代码不会被打断。
可见性:线程1对数据的修改,线程2实时可见。
指令重排:单线程下代码顺序在不影响结果下代码会随机执行其优化作用,在多线程环境下会引起数据不一致。
关键字 volatile 保证可见性,禁止指令重排,不保证原子性。
关键字 synchronized 保证原子性,保证可见性,禁止指令重排。
参考线程交互内存模型:
Q1:i++;操作在多线程的环境下,数据不一致,如何一致?
A1:采用原子整型(AtomicInteger)做i++操作。
Q2:原子整型是如何保证多线程环境下数据安全的?
A2:利用compare and swap 原理保证。
Q3:compare and swap缺点
A3:1.底层会一直重复判断参数是否与期望值一致,性能开支大。
2.只能保证一个共享变量的原子性操作。
3.ABA问题。
线程池原理及使用
线程池=核心处理线程数+最大处理线程数+阻塞队列+拒绝策略
线程池优势
线程的复用减少资源消耗极端情况下防止Cpu过载,不需要管理具体线程交由线程池管理。
线程池底层运行原理
线程池最长的工作流程: 核心线程数已满>任务进入阻塞队列>阻塞队列已满>开启最大线程池>阻塞队列+最大线程数已满>拒绝策略
线程池内部处理图:
阻塞队列原理
原理:生产者消费者模式。
优势:通过无锁即能控制线程的顺序执行。
技术实现:通过阻塞队列BlockingQueue实现。
传统生产者消费者模式:
public class four {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public Integer num=0;
public void add(){
lock.lock();
try {
while(num!=0){
condition.await();
//System.out.println("生产完毕!!等待消费"+Thread.currentThread().getName());
}
num++;
System.out.println("开始生产!!线程是:"+Thread.currentThread().getName());
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void sub(){
lock.lock();
try {
while(num==0){
condition.await();
//System.out.println("消费完毕!!等待生产"+Thread.currentThread().getName());
}
num--;
System.out.println("开始消费!!线程是:"+Thread.currentThread().getName());
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
four four = new four();
new Thread(()->{
for (int i = 0; i <5 ; i++) {
four.add();
}
},"AAA").start();
new Thread(()->{
for (int i = 0; i <5 ; i++) {
four.sub();
}
},"BBB").start();
}
}
无锁版:
public class five {
private volatile Boolean Flag=true;
private BlockingQueue<String> blockingQueue=null;
private AtomicInteger atomicInteger = new AtomicInteger(0);
public void add() {
try {
Boolean offer = false;
while (Flag) {
String value = atomicInteger.incrementAndGet() + "";
synchronized (this) {
offer = blockingQueue.offer(value, 2, TimeUnit.SECONDS);
System.out.println();
System.out.println();
System.out.println();
if (offer) {
System.out.println("线程" + Thread.currentThread().getName() + "生产产品(编号" + value + ")成功");
} else {
System.out.println("线程" + Thread.currentThread().getName() + "生产失败");
}
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println("收到指令停止生产");
} catch(Exception e){
e.printStackTrace();
}
}
public void sub(){
try {
String poll = null;
while(Flag){
poll = blockingQueue.poll(2, TimeUnit.SECONDS);
if(poll!=null){
System.out.println("线程"+Thread.currentThread().getName()+"消费产品(编号"+poll+")成功");
}else {
System.out.println("线程"+Thread.currentThread().getName()+"消费失败");
Flag = false;
return;
}
TimeUnit.SECONDS.sleep(1);
}
System.out.println("收到指令停止消费");
} catch (Exception e) {
e.printStackTrace();
}
}
public void stop(){
System.out.println("要求停止所有动作");
Flag=false;
}
public five(BlockingQueue<String> blockingQueue) {
this.blockingQueue = blockingQueue;
}
public static void main(String[] args) throws Exception{
five five = new five(new SynchronousQueue<>());
new Thread(()->{
five.add();
},"AAA").start();
new Thread(()->{
five.sub();
},"BBB").start();
TimeUnit.SECONDS.sleep(5);
five.stop();
}
}
最大线程数的合理配置
cpu密集型:cpu数+1
io密集型:cpu数/(1-阻塞系数) 阻塞系数=0.8~0.9
各种锁机制
常用锁类型:公平锁/非公平锁;可重入锁(递归锁);自旋锁;独占锁/共享锁
自旋锁实例:
//模拟自旋锁
//利用compare and swap(比较并交换)机制实现自旋锁
public class spinLock {
private AtomicReference<Thread> reference = new AtomicReference<>();
public void mylock(){
Thread thread = Thread.currentThread();
System.out.println("进入加锁阶段");
while(!reference.compareAndSet(null,thread))
{
//System.out.println("尝试获取锁");
}
System.out.println("加锁完成阶段");
}
public void unlock(){
Thread thread = Thread.currentThread();
reference.compareAndSet(thread,null);
System.out.println("完成解锁");
}
public static void main(String[] args) {
spinLock lock = new spinLock();
new Thread(()->{
try {
lock.mylock();
System.out.println("进入5秒等待时间");
Thread.sleep(5000);
System.out.println("处理业务操作");
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}."线程1").start();
new Thread(()->{
lock.mylock();
System.out.println("处理业务操作");
lock.unlock();
},"线程2").start();
}
//运行结果:
进入加锁阶段
加锁完成阶段
进入5秒等待时间
进入加锁阶段
处理业务操作
完成解锁
加锁完成阶段
处理业务操作
完成解锁
}
独占锁/共享锁实例:
//模拟读写锁
//读-读 共享锁
//读-写 独占锁
//写-写 独占锁
public class ReadWriteLock {
HashMap<String,Object> myMap = new HashMap<>();
ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
private void put(String s,Object obj){
myLock.writeLock().lock();
System.out.println("当前写线程:"+Thread.currentThread().getName());
myMap.put(s,obj);
System.out.println("数据写入成功!当前写线程:"+Thread.currentThread().getName());
myLock.writeLock().unlock();
}
private void get(String s){
myLock.readLock().lock();
Object o = myMap.get(s);
System.out.println("获取到的数据:"+o);
myLock.readLock().unlock();
}
public static void main(String[] args) {
ReadWriteLock readWriteLock = new ReadWriteLock();
for (int i = 0; i <10 ; i++) {
int j = i;
new Thread(()->{
readWriteLock.put(j+"",j);
readWriteLock.get(j+"");
},"线程"+j).start();
}
}
//运行结果:
当前写线程:线程0
数据写入成功!当前写线程:线程0
当前写线程:线程1
数据写入成功!当前写线程:线程1
获取到的数据:0
获取到的数据:1
当前写线程:线程2
数据写入成功!当前写线程:线程2
当前写线程:线程3
数据写入成功!当前写线程:线程3
当前写线程:线程4
数据写入成功!当前写线程:线程4
当前写线程:线程5
数据写入成功!当前写线程:线程5
当前写线程:线程6
数据写入成功!当前写线程:线程6
当前写线程:线程7
数据写入成功!当前写线程:线程7
当前写线程:线程8
数据写入成功!当前写线程:线程8
当前写线程:线程9
数据写入成功!当前写线程:线程9
获取到的数据:9
获取到的数据:3
获取到的数据:5
获取到的数据:2
获取到的数据:8
获取到的数据:7
获取到的数据:6
获取到的数据:4
}