java并发编程原理

本文详细介绍了Java中创建和管理多线程的多种方式,包括继承Thread类、实现Runnable接口、使用Lambda表达式等,并探讨了线程的安全性、活跃性和性能问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cmd看字节码命令 javap -verbose xx.class


start-----readtorun-----run-------stop
                     wait|sleep
|
bolcked






创建线程的多种方式:
1.继承Thread类


extends Thread
重写run方法
@Override
public void run(){
//getName()可以获取线程名称
}


jkd6后使用interrupt()线程中断,判断使用interrupted() 
stop并未真正中断,线程锁以及资源并未真正释放 
setDaemon(true);守护线程
作用:当主线程结束,该线程任务没有执行完毕也会随主线程一样结束


拓展:
ThreadGroup线程组
可以创建一个线程组,然后把线程加到线程组中
树状结构


2.实现Runnable接口
优点:面向接口编程
implements Runnable
和继承Thread类一样它也要实现run接口
作为线程任务存在
  




3.匿名内部类的方式




//第一种:
new Thread(){
public void run(){
System.out.println("Thread");
}
}.start();
//第二种:
new Thread(new Runnable(){
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Runnable");
}
}).start();
拓展:
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("Runnable");
}
}){
public void run(){
System.out.println("Thread");
}
}.start();
new Thread的时候,会把()里面Runable带到Thread类中的构造方法,
经过init初始化等一系列的赋值,Thread类中属性target会得到赋值,
然后执行start,会去找Thread(父)类中的Run方法,然而
{}之间的是子类,按照java基础语法多态可知,此时父类中的Run方法并没什么卵用,target只是陪玩,
会按照子类中的Run方法来执行
根据java语法多态,先执 




4.带返回值的线程
详解:
http://blog.youkuaiyun.com/javazejian/article/details/50896505


实现callable方法 
implements  Callable<T>
@Override 
public T call() throws Exception{}


结合FutureTask该类实现了Runnable接口




5.定时器
Timer timer = new Timer();
timer.schedule();/指定日期、指定延时、指定第一次日期间此后间隔执行
延时多长时间此后间隔执行
TimerTask类实现了Runable方法


缺点:不可控,当任务没有执行完毕或者要提交不同任务时,
quartz框架可以实现


6.线程池的实现
Executor threadPool = Executors.newFixedThreadPool(10); 
newFixedThreadPool(10)创建固定数量线程 
threadPool.execute(new Runnable(){
public void run(){
}
})
ExecutorService threadPool =Excutors.newCachedThreadPool()根据线程任务不够用就创建,够用就回收
threadPool.shutdown();停掉线程池


7.Lambda表达式实现
函数式编程
优点:代码简洁、实现方便、对并发支持性好性能高






8.Spring实现多线程
jdk8新特性
使用Maven构建项目,pom.xml配置jdk以及spring
@Configuration
@ComponentScan("") 扫描包
@EnableAsync
构建Config


@Service注释类
@Async 注释方法
构建方法




线程带来的风险:
1.线程安全性问题
多线程环境下
多个线程共享一个资源
对资源进行非原子性操作


什么时候出现:多线程环境下;多个线程共享一个资源;对资源进行读写操作
解决:方法加关键字synchronized






Synchronized的原理与使用
内置锁
每一个java中的对象都是一个内置锁,java在进入同步代码块之前都必须先获得锁,
也就是获得内置锁,获得之后就可以执行同步代码块,那其它线程就
无法获得了,只有等它释放了锁其他线程才能进来,就相当于被synchronzed
修饰的方法体相当于一个原子性操作,这样就保证了线程安全性。
互斥锁(一个线程进来,那么另一个线程不能进来)




Synchronized使用 
修饰普通方法(放在普通方法上,那么内置锁就是当前类的实例)
修饰静态(static)方法(放在普通方法上,那么内置锁就是当前的class字节码对象)
修饰代码块 synchronized(Object){}


Synchronized保证线程安全的原理(jvm层面)
通过monitorenter进入和monitorexit退出
无论什么情况,这个锁都会释放


任何对象都可以作为锁,锁信息存在于对象头中
对象头中的信息
1Mark Word 对象的哈希值和锁信息
2Class Metadata Address 类型地址
3Array Length 数组对象多了一个数组长度


jdk1.6后引入了偏向锁、轻量级锁、重量级锁
偏向锁
出现原因:
每次获取锁和释放锁会浪费资源
很多情况下,竞争锁不是由多个线程,而是由一个线程在使用。
偏向锁的markword会记录:线程id、Epoch、对象的分带
年龄信息、是否是偏向锁、锁标志位
适用场景:
只有一个线程在访问同步代码块的场景
很多情况下不会提高性能


轻量级锁
自旋:自己不停的旋转等待去执行,旋的是cpu的时间片,也就是空转cpu,
一直等待被唤醒之后
多个线程可以同时


锁重入
syncronized和lock都是重入锁
Demo:
public synchronized void a(){
  System.out.println("a");
  b();
}
public synchronized void b(){
  System.out.println("b");
}
上例中b()是可以执行的,这就是锁的重入
当是同一个对象的两个锁,是可以锁住的
当锁对应的是不同的对象,那么就不能锁住




Thread.activerCount();线程活跃数








2.活跃性问题
死锁:都有对方的资源但是都不释放,导致进程无法进行
产生原因:当一个线程永远都只有一把锁,其它线程尝试获得该把锁
的时候,也就发生了死锁,无非就是争夺资源
cmd输入命令jconle可以检测死锁
jvm对死锁处理能力较弱,第一死锁不会每次都发生,第二发生后在jvm中
线程就死掉了,jvm不会对其释放掉,而数据库这方面处理的很好


demo:
private Object obj1 = new Object();
private Object obj2 = new Object();
public void a(){
  synchronized(obj2){
synchronized(obj1){
System.out.println("a");
}
  }
}
public void b(){
  synchronized(obj1){
synchronized(obj2){
System.out.println("b");
}
  }
}


 
饥饿:线程有优先级,优先级低的可能一直得不到CPU


高优先级吞噬所有低优先级的CPU时间片
setPriority() 设置优先级
线程被永久堵塞在一个等待进入同步块的状态
等待的线程永远不被唤醒


如何尽量避免饥饿问题
设置合理的优先级
使用锁来代替synchronized




活锁:类似平时两人相对而走,循环同时避让


3.性能问题
cpu会为各个线程分配时间片,
当这个任务在这个时间片中执行完了之后,
cpu会执行下一个,因为时间片很短,所以我们看起来这么多任务
是一块执行的,也就是转的非常快,转的过程就是上下文切换,
cpu通过一定的算法循环执行这些任务,但是切换的时候
要保存当前任务的执行状态,以便下一次执行能够加载出来
继续执行,所以在转换的过程中上下文切换是蛮消耗资源的









龙果 java并发编程原理实战 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的方式案例演示(一)带返回值的方式00:17:12分钟 | 第8节多种创建线程的方式案例演示(二)使用线程池00:15:40分钟 | 第9节Spring对并发的支持:Spring的异步任务00:11:10分钟 | 第10节使用jdk8提供的lambda进行并行计算00:14:22分钟 | 第11节了解多线程所带来的安全风险00:13:16分钟 | 第12节从线程的优先级看饥饿问题00:18:42分钟 | 第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节synchronized保证线程安全的原理(理论层面)00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题与线程安全性深入解析00:27:15分钟 | 第17节理解自旋锁,死锁与重入锁00:24:58分钟 | 第18节深入理解volatile原理与使用00:28:30分钟 | 第19节JDK5提供的原子类的操作以及实现原理00:27:10分钟 | 第20节Lock接口认识与使用00:19:54分钟 | 第21节手动实现一个可重入锁00:26:31分钟 | 第22节AbstractQueuedSynchronizer(AQS)详解00:49:04分钟 | 第23节使用AQS重写自己的锁00:31:04分钟 | 第24节重入锁原理与演示00:12:24分钟 | 第25节读写锁认识与原理00:18:04分钟 | 第26节细读ReentrantReadWriteLock源码00:30:38分钟 | 第27节ReentrantReadWriteLock锁降级详解00:13:32分钟 | 第28节线程安全性问题简单总结00:15:34分钟 | 第29节线程之间的通信之wait/notify00:32:12分钟 | 第30节通过生产者消费者模型理解等待唤醒机制00:20:50分钟 | 第31节Condition的使用及原理解析00:17:40分钟 | 第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第38节并发工具类CyclicBarrier 详解00:11:52分钟 | 第39节并发工具类Semaphore详解00:17:27分钟 | 第40节并发工具类Exchanger详解00:13:47分钟 | 第41节CountDownLatch,CyclicBarrier,Semaphore源码解析00:29:57分钟 | 第42节提前完成任务之FutureTask使用00:11:43分钟 | 第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器CopyOnWriteArrayList原理与使用00:15:52分钟 | 第48节并发容器ConcurrentLinkedQueue原理与使用00:31:03分钟 | 第49节Java中的阻塞队列原理与使用00:26:18分钟 | 第50节实战:简单实现消息队列00:11:07分钟 | 第51节并发容器ConcurrentHashMap原理与使用00:38:22分钟 | 第52节线程池的原理与使用00:42:49分钟 | 第53节Executor框架详解00:36:54分钟 | 第54节实战:简易web服务器(一)00:55:34分钟 | 第55节实战:简易web服务器(二)00:24:36分钟 | 第56节JDK8的新增原子操作类LongAddr原理与使用00:17:45分钟 | 第57节JDK8新增锁StampedLock详解00:29:37分钟 | 第58节重排序问题00:23:19分钟 | 第59节happens-before简单概述00:15:17分钟 | 第60节锁的内存语义00:13:54分钟 | 第61节volatile内存语义00:12:04分钟 | 第62节final域的内存语义00:34:07分钟 | 第63节实战:问题定位00:07:48分钟
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值