-
2021-03-14 22:38:19
java中使用多线程不能明显提高程序效率的一些原因.
使用多个线程来处理多任务的时候,效率肯定是有提高的.但是必须要慎用,否则容易出现问题.
1.多线程主要是为了充分利用多核cpu,大内存这些资源.
如果你的硬件跟不上,只有一个cpu,那么多线程从并发变成了串行了,另外再加上线程上下文切换的时候,那你就得不偿失了.
2.原子问题
如果多线程是同步操作一个原子数据,(多个线程同步去处理一个加锁的对象),那效率肯定不会提升,就好像1个人去做1件事和多个人排队去做一件事效率是一样的;
3.线程的个数对于一个应用程序来讲的话,往往会有一个临界值。
临界资源的访问问题,程序中临界区的指令一般来说越少越好,最好不要在临界区中做一些重量级的事情,例如说数据库,写文件,读文件!
4.对硬盘的读写有特殊的地方。
对磁盘进行多线程处理的时候,效率会急速下降!!
因为不同文件的读写,会造成磁头的频繁转换,磁头的频繁转换要比读取磁盘的时间更长。
所以这种情况下,最好有个线程去读取文件,其他的线程去处理文件数据中的业务逻辑处理.
5.操作系统的IO通道数量的影响
采用普通的File文件API来读写多文件.使用多线程的话很大程度上也不会提高效率.
因为文件,网络等流的读写都需要操作IO通道,而操作系统的IO通道数量是固定的。
我们假设你的电脑只有一个IO通道,如果你打开一个文件流并进行读写,则占用了一个IO通道,如果你又打开一个文件流,则第二个文件流需要等待第一个文件关闭通道才能真正意义上的进行读写。 所以实际上,你打开多个文件同时进行读写时就是在串行单线程操作。
解决的办法是采用 NIO: java.nio (Java 2 Platform SE v1.4.2)
NIO的意思当然就是同时开启N个IO通道了,如果你的机器硬件的确只支持同时打开一个通道的话,Java虚拟器会帮你做虚拟协调NIO比普通IO技术至少快30%.
具体可以查看JAVA文件NIO的文档.
普通方式写文件先得到FileOutputStream,然后直接设用 os.write(bytes);
而现在不同点在于先得到一个Channel再建构一个Bytebuffer,再用两者完成任务,java虚拟机帮你完成剩下的CPU和IO任务调度.
其实这个方式也就是异步的样子了,实际里很多前端MVC框架如JSF的实现primefaces,已经封装了,也没法用.如果要用的话也是用Apache NIO 框架 Mina.
更多相关内容 -
Java中的锁原理、锁优化、CAS、AQS详解
2021-03-13 11:28:102、锁实现的基本原理2.1、volatileJava编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。...来源 | https://urlify.cn/VJNZNj
1、为什么要用锁?
锁-是为了解决并发操作引起的脏读、数据不一致的问题。
2、锁实现的基本原理
2.1、volatileJava编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。
volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。
2.2、synchronizedsynchronized通过锁机制实现同步。
先来看下利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁。
具体表现为以下3种形式。对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的Class对象。
对于同步方法块,锁是Synchonized括号里配置的对象。
当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。
2.2.1 synchronized实现原理synchronized是基于Monitor来实现同步的。
Monitor从两个方面来支持线程之间的同步:互斥执行
协作
1、Java 使用对象锁 ( 使用 synchronized 获得对象锁 ) 保证工作在共享的数据集上的线程互斥执行。
2、使用 notify/notifyAll/wait 方法来协同不同线程之间的工作。
3、Class和Object都关联了一个Monitor。
线程进入同步方法中。
为了继续执行临界区代码,线程必须获取 Monitor 锁。如果获取锁成功,将成为该监视者对象的拥有者。任一时刻内,监视者对象只属于一个活动线程(The Owner)
拥有监视者对象的线程可以调用 wait() 进入等待集合(Wait Set),同时释放监视锁,进入等待状态。
其他线程调用 notify() / notifyAll() 接口唤醒等待集合中的线程,这些等待的线程需要重新获取监视锁后才能执行 wait() 之后的代码。
同步方法执行完毕了,线程退出临界区,并释放监视锁。
参考文档:https://www.ibm.com/developerworks/cn/java/j-lo-synchronized
2.2.2 synchronized具体实现
1、同步代码块采用monitorenter、monitorexit指令显式的实现。
2、同步方法则使用ACC_SYNCHRONIZED标记符隐式的实现。
通过实例来看看具体实现:publicclassSynchronizedTest{
publicsynchronizedvoidmethod1(){
System.out.println("Hello World!");
}
publicvoidmethod2(){
synchronized(this){
System.out.println("Hello World!");
}
}
}
javap编译后的字节码如下:
monitorenter
每一个对象都有一个monitor,一个monitor只能被一个线程拥有。当一个线程执行到monitorenter指令时会尝试获取相应对象的monitor,获取规则如下:如果monitor的进入数为0,则该线程可以进入monitor,并将monitor进入数设置为1,该线程即为monitor的拥有者。
如果当前线程已经拥有该monitor,只是重新进入,则进入monitor的进入数加1,所以synchronized关键字实现的锁是可重入的锁。
如果monitor已被其他线程拥有,则当前线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor。
monitorexit
只有拥有相应对象的monitor的线程才能执行monitorexit指令。每执行一次该指令monitor进入数减1,当进入数为0时当前线程释放monitor,此时其他阻塞的线程将可以尝试获取该monitor。
2.2.3 锁存放的位置
锁标记存放在Java对象头的Mark Word中。
2.2.3 synchronized的锁优化
JavaSE1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。
在JavaSE1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。
锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
偏向锁:无锁竞争的情况下为了减少锁竞争的资源开销,引入偏向锁。
轻量级锁:轻量级锁所适应的场景是线程交替执行同步块的情况。
锁粗化(Lock Coarsening): 也就是减少不必要的紧连在一起的unlock,lock操作,将多个连续的锁扩展成一个范围更大的锁。
锁消除(Lock Elimination): 锁削除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行削除。
适应性自旋(Adaptive Spinning): 自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间,比如100个循环。另一方面,如果对于某个锁,自旋很少成功获得过,那在以后要获取这个锁时将可能省略掉自旋过程,以避免浪费处理器资源。
2.2.4 锁的优缺点对比
2.3、CASCAS,在Java并发应用中通常指CompareAndSwap或CompareAndSet,即比较并交换。
1、CAS是一个原子操作,它比较一个内存位置的值并且只有相等时修改这个内存位置的值为新的值,保证了新的值总是基于最新的信息计算的,如果有其他线程在这期间修改了这个值则CAS失败。CAS返回是否成功或者内存位置原来的值用于判断是否CAS成功。
2、JVM中的CAS操作是利用了处理器提供的CMPXCHG指令实现的。
优点:竞争不大的时候系统开销小。
缺点:循环时间长开销大。
ABA问题。
只能保证一个共享变量的原子操作。
3、Java中的锁实现
3.1、队列同步器(AQS)队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架。
3.1.1、它使用了一个int成员变量表示同步状态。
3.1.2、通过内置的FIFO双向队列来完成获取锁线程的排队工作。同步器包含两个节点类型的应用,一个指向头节点,一个指向尾节点,未获取到锁的线程会创建节点线程安全(compareAndSetTail)的加入队列尾部。同步队列遵循FIFO,首节点是获取同步状态成功的节点。
未获取到锁的线程将创建一个节点,设置到尾节点。如下图所示:
首节点的线程在释放锁时,将会唤醒后继节点。而后继节点将会在获取锁成功时将自己设置为首节点。如下图所示:
3.1.3、独占式/共享式锁获取独占式:有且只有一个线程能获取到锁,如:ReentrantLock。
共享式:可以多个线程同时获取到锁,如:CountDownLatch
独占式每个节点自旋观察自己的前一节点是不是Header节点,如果是,就去尝试获取锁。
独占式锁获取流程:
共享式:共享式与独占式的区别:
共享锁获取流程:
4、锁的使用
4.1、ConcurrentHashMap的实现原理及使用(1.7)
ConcurrentHashMap类图
ConcurrentHashMap数据结构
结论:ConcurrentHashMap使用的锁分段技术。首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
-
redis高并发导致读写变慢(redis多线程)
2021-08-13 06:16:12package ...import java.util.HashSet;import java.util.Set;import org.apache.log4j.Logger;import com.sinosoft.sysframework.reference.AppConfig;import com.sinosoft.utility.s...package com.sinosoft.prpall.pubfun.redis;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import com.sinosoft.sysframework.reference.AppConfig;
import com.sinosoft.utility.string.Str;
import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
/**
* Redis 工具类
* @author caspar
* https://blog.csdn.net/tuposky
*/
public class RedisUtil {
protected static Logger logger = Logger.getLogger(RedisUtil.class);
//redis服务器地址
private static String redisIP = AppConfig.get("Redis.SentinelServiceIP");
//redis服务器端口
private static int redisPort = Integer.parseInt(AppConfig.get("Redis.Port"));
//主服务器名
private static String master = AppConfig.get("Redis.SentinelMasterName");
//访问密码
private static String AUTH = AppConfig.get("Redis.Auth");
//连接的DB序号
private static int dbSerialNo = Integer.parseInt(Str.chgStrZero(AppConfig.get("Redis.DBSerialNo")));
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = Integer.parseInt(Str.chgStrZero(AppConfig.get("Redis.MaxActive")));
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = Integer.parseInt(Str.chgStrZero(AppConfig.get("Redis.MaxIdle")));
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = Integer.parseInt(Str.chgStrZero(AppConfig.get("Redis.WaitTime")));
//超时时间
private static int TIMEOUT = Integer.parseInt(Str.chgStrZero(AppConfig.get("Redis.TimeOut")));
//使用redis服务器类型:1-测试(单机模式),2-生产(哨兵模式)
private static String redisType = AppConfig.get("Redis.RedisType");
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;
//将Jedispool初始化到 堆内存 中通过 volatile 变量使线程从主存中读取变量的值
private volatile static JedisSentinelPool jedisPool = null;
private volatile static JedisPool jedisPoolS = null;
//利用AtomicBoolean进行 CAS方法加锁 ,保证单一初始化
private static AtomicBoolean initFlag = new AtomicBoolean(false);
/**
* redis过期时间,以秒为单位
*/
public final static int EXRP_HOUR = 60*60; //一小时
public final static int EXRP_DAY = 60*60*24; //一天
public final static int EXRP_MONTH = 60*60*24*30; //一个月
/**
* 初始化Redis连接池
*/
static{
// 利用CAS方法加锁,保证单一初始化
if(initFlag.compareAndSet(false, true)) {
try {
logger.info(Thread.currentThread().getId() + " init pool");
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
String[] redisIPList = redisIP.split(",");
Set sentinels=new HashSet();
for(int i=0;i
sentinels.add(redisIPList[i]);
}
//使用redis服务器类型:1-测试(单机模式),2-生产(哨兵模式)
if("1".equals(redisType)) {
jedisPoolS = new JedisPool(config, redisIP, redisPort, 100000, AUTH);
}else {
jedisPool = new JedisSentinelPool(master, sentinels, config, TIMEOUT, AUTH);
}
} catch (Exception e) {
// 初始化失败,放开标志让其它线程尝试初始化池
initFlag.set(false);
e.printStackTrace();
logger.error("First create JedisPool error : "+e);
}
}else {
// 等待第一个进入的线程初始化完毕
while(jedisPoolS == null && jedisPool == null) {
logger.info(Thread.currentThread().getId() + " 等待其它线程完成连接池初始化 ...");
}
}
}
/**
* 同步获取Jedis实例
* @return Jedis
*/
public static Jedis getJedis() {
Jedis jedis = null;
try {
//使用redis服务器类型:1-测试(单机模式),2-生产(哨兵模式)
if("1".equals(redisType)) {
if (jedisPoolS != null) {
jedis = jedisPoolS.getResource();
jedis.select(dbSerialNo);
}
}else {
if (jedisPool != null) {
jedis = jedisPool.getResource();
jedis.select(dbSerialNo);
}
}
} catch (Exception e) {
e.printStackTrace();
logger.error("Get jedis error : ", e);
throw e;
}
return jedis;
}
public void returnJedisResource(Jedis jedis){
if(jedis != null){
jedis.close();
}
}
}
-
Java 多线程编程(锁优化)
2021-03-16 02:21:11加锁会带来性能上的损坏,似乎是众所周知的事情。然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程。如果只有一个线程竞争锁,此时并不存在多线程竞争的情况,那么JVM会进行优化,那么这时...转:https://mp.weixin.qq.com/s/lDuguEhuWiLY8ofBRy3tZA
并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问。
加锁会带来性能上的损坏,似乎是众所周知的事情。
然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程。
如果只有一个线程竞争锁,此时并不存在多线程竞争的情况,那么JVM会进行优化,那么这时加锁带来的性能消耗基本可以忽略。
因此,规范加锁的操作,优化锁的使用方法,避免不必要的线程竞争,不仅可以提高程序性能,也能避免不规范加锁可能造成线程死锁问题,提高程序健壮性。
下面阐述几种锁优化的思路。
01
尽量不要锁住方法
在普通成员函数上加锁时,线程获得的是该方法所在对象的对象锁。此时整个对象都会被锁住。
这也意味着,如果这个对象提供的多个同步方法是针对不同业务的,那么由于整个对象被锁住,一个业务业务在处理时,其他不相关的业务线程也必须wait。
下面的例子展示了这种情况:
LockMethod类包含两个同步方法,分别在两种业务处理中被调用:
public class LockMethod {
public synchronized void busyA() {
for (int i = 0; i < 10000; i++) {
System.out.println(Thread.currentThread().getName() + "deal with bussiness A:"+i);
}
}
public synchronized void busyB() {
for (int i = 0; i < 10000; i++) {
System.out.println(Thread.currentThread().getName() + "deal with bussiness B:"+i);
}
}
}
BusyA是线程类,用来处理A业务,调用的是LockMethod的busyA()方法:
public class BusyA extends Thread {
LockMethod lockMethod;
void deal(LockMethod lockMethod){
this.lockMethod = lockMethod;
}
@Override
public void run() {
super.run();
lockMethod.busyA();
}
}
BusyB是线程类,用来处理B业务,调用的是LockMethod的busyB()方法:
public class BusyB extends Thread {
LockMethod lockMethod;
void deal(LockMethod lockMethod){
this.lockMethod = lockMethod;
}
@Override
public void run() {
super.run();
lockMethod.busyB();
}
}
TestLockMethod类,使用线程BusyA与BusyB进行业务处理:
public class TestLockMethod
public static void main(String[] args) {
LockMethod lockMethod = new LockMethod();
BUSSA bussa = new BUSSA();
BUSSB bussb = new BUSSB();
bussa.deal(lockMethod);
bussb.deal(lockMethod);
bussa.start();
bussb.start();
}
}
运行程序,可以看到在线程bussa 执行的过程中,bussb是不能够进入函数 busyB()的,因为此时lockMethod 的对象锁被线程bussa获取了。
02
缩小同步代码块,只锁数据
有时候为了编程方便,有些人会synchnoized很大的一块代码。
如果这个代码块中的某些操作与共享资源并不相关,那么应当把它们放到同步块外部,避免长时间的持有锁,造成其他线程一直处于等待状态。
尤其是一些循环操作、同步I/O操作。不止是在代码的行数范围上缩小同步块,在执行逻辑上,也应该缩小同步块。
例如多加一些条件判断,符合条件的再进行同步,而不是同步之后再进行条件判断,尽量减少不必要的进入同步块的逻辑。
03
锁中尽量不要再包含锁
这种情况经常发生,线程在得到了A锁之后,在同步方法块中调用了另外对象的同步方法,获得了第二个锁.
这样可能导致一个调用堆栈中有多把锁的请求,多线程情况下可能会出现很复杂、难以分析的异常情况,导致死锁的发生。
下面的代码显示了这种情况:
synchronized(A){
synchronized(B){
}
}
或是在同步块中调用了同步方法:
synchronized(A){
B b = objArrayList.get(0);
b.method(); //这是一个同步方法
}
解决的办法是跳出来加锁,不要包含加锁:
{
B b = null;
synchronized(A){
b = objArrayList.get(0);
}
b.method();
}
04
将锁私有化,在内部管理锁
把锁作为一个私有的对象,外部不能拿到这个对象,更安全一些。
对象可能被其他线程直接进行加锁操作,此时线程便持有了该对象的对象锁。
例如下面这种情况:
class A {
public void method1() {
}
}
class B {
public void method1() {
A a = new A();
synchronized (a) { //直接进行加锁
a.method1();
}
}
}
这种使用方式下,对象a的对象锁被外部所持有,让这把锁在外部多个地方被使用是比较危险的,对代码的逻辑流程阅读也造成困扰。
一种更好的方式是在类的内部自己管理锁,外部需要同步方案时,也是通过接口方式来提供同步操作:
class A {
private Object lock = new Object();
public void method1() {
synchronized (lock){
}
}
}
class B {
public void method1() {
A a = new A();
a.method1();
}
}
05
进行适当的锁分解
考虑下面这段程序:
public class GameServer {
public Map> tables = new HashMap>();
public void join(Player player, Table table) {
if (player.getAccountBalance() > table.getLimit()) {
synchronized (tables) {
List tablePlayers = tables.get(table.getId());
if (tablePlayers.size() < 9) {
tablePlayers.add(player);
}
}
}
}
public void leave(Player player, Table table) {/*省略*/}
public void createTable() {/*省略*/}
-
java问题排查总结
2021-03-09 02:14:18前些天发现:http://hellojava.info/这个站点,关于java问题排查分析总结... Hashmap 并发情况下未加锁导致OOM嗯,死循环很常见,OOM也会有,序列化时HashMap.writeObject 一直执行生成巨大的数组。2. Direct Bytebuf... -
Java中的锁机制
2021-06-07 20:57:14锁机制无处不在,锁机制是实现线程同步的基础,锁机制并不是Java锁独有的,其他各种计算机语言中也有着锁机制相关的实现,数据库中也有锁的相关内容。这篇文章就是从Java入手,深入学习、理解Java中的锁机制,提升... -
Java 基础高频面试题(2021年最新版)
2021-03-31 23:39:26最新 Java 基础高频面试题 -
为什么你的SQL执行很慢
2019-05-29 18:35:13为什么你的SQL执行很慢SQL语句执行很慢原因分析1.没走索引1.1对索引字段进行了计算操作1.2存在隐式类型转换1.3 like操作1.4隐式编码转换1.5 not in 操作1.6扫描行数太多2.等待锁3.刷脏页4.执行undo log索引设计原则... -
10万字208道Java经典面试题总结(附答案)
2021-08-01 16:05:55JDK(Java Development Kit),Java开发工具包 JRE(Java Runtime Environment),Java运行环境 JDK中包含JRE,JDK中有一个名为jre的目录,里面包含两个文件夹bin和lib,bin就是JVM,lib就是JVM工作所需要的类库。... -
MySQL调大sort_buffer_size,并发量一大,查询排序为啥又会变慢
2021-12-21 16:51:45导读 大家可以想看看这条SQL语句思考一下: SELECT * FROM user WHERE user_name LIKE "%am%" AND age >...你可能已经发现,这条SQL其实只需要取前50个排好序的用户,但是,上面的执行过程确对... -
『图解Java并发编程系列』10张图告诉你Java并发多线程那些破事
2021-04-28 20:56:52头发很多的程序员:『师父,我已经使用了多线程,为什么接口还变慢了?』 架构师:『去给我买杯咖啡,我写篇文章告诉你』 ……吭哧吭哧买咖啡去了 在实际工作中,错误使用多线程非但不能提高效率还可能使程序... -
Java面试题及答案整理( 2022最新版,持续更新)
2021-11-08 16:34:49发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全,希望对大家有帮助哈~ Java面试永远是程序员迈向成功的第一个门槛,想要面试成功,各种面试题的洗礼是必不可少的,下面就来... -
【Java 多线程】多线程带来的的风险-线程安全、多线程五个经典案例
2022-03-26 22:47:19正式因为这样的随机性,就可能导致程序的执行出现一些 bug 如果因为这样的调度随机性引入了 bug,就认为代码是线程不安全的,如果是因为这样的调度随机性,也没有带来 bug,就认为代码是线程安全的 这里的线程安全指... -
python运行非常慢的解决-python执行太慢
2020-11-01 13:13:54假如 load 完成还没计算,这时候线程切换了,其他线程修改了 a 的值,然后切换回来继续执行计算和存储 a,那么就会造成线程不安全。 所以多线程同时操作一个变量的时候,依然需要加锁。 “python 一次只能运行一个... -
Java面试题大全(2021版)
2020-11-25 11:55:31发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全,希望对大家有帮助哈~ 本套Java面试题大全,全的不能再全,哈哈~ 一、Java基础知识面试题 1、Java概述 ①. 何为编程 ... -
某Java大佬在地表最强Java企业(阿里)面试总结
2020-08-23 19:48:06验证 (验证阶段作用是保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害,如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常。 1.文件格式验证: 验证字节流文件是否符合Class文件... -
java 并发问题存在的原因 & 解决方案
2022-04-08 16:59:44java 并发存在的原因 & 解决方案 -
Thinking in Java读书笔记
2019-07-31 18:37:16Thinking in Java读书笔记(IO和并发除外) 1.1、类中所有的private方法都隐式地指定为final的,由于其他类无法取用private方法,所以也就无法覆盖它;private方法无法被重写,继承对应private的方法无效,private... -
Java多线程系列—多线程带来的问题(05)
2021-05-05 14:08:35多线程带来的问题 为什么需要多线程 其实说白了,时代变了,...Java 中的线程与 CPU 单核执行是一对一的,即单个处理器同一时间只能处理一个线程的执行;而 CPU 是通过时间片算法来执行任务的,不同的线程活跃状态不同 -
java面试中jvm执行子系统详细分析(三)
2020-06-29 14:41:28JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 引入Java语言虚拟机后,Java语言在不同平台上... -
一年Java经验应该会些什么
2020-12-23 09:47:091.引言 毕业已经一年有余,这一年里特别感谢技术管理人员...不重基础,总觉得很多基础东西不需要再看了,其实不懂的地方很多,计算机程序方面任何一个结果都必有原因,不要只会用不知道原理,那是加工厂出来的。现在id -
java集合的并发问题
2021-03-02 23:29:51文章目录一、Java集合中的快速失败机制解决并发修改问题的方法二、java并发编程volatile互斥锁sychronized公平锁/非公平锁可重入锁独享锁/共享锁乐观锁/悲观锁偏向锁/轻量级锁/重量级锁自旋锁锁消除synchronized和... -
在JAVA中线程到底起到什么作用以及线程加锁的方式
2018-04-25 17:11:10这是javaeye上非常经典的关于线程的帖子,写的非常通俗易懂的,适合任何读计算机的同学. 线程同步我们可以在计算机上运行各种计算机... 当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需... -
Java多线程6:ReentrantLock同步锁
2021-09-07 16:08:33前言:Java除了使用关键字synchronized外,还可以使用ReentrantLock实现独占锁的功能。而且ReentrantLock相比synchronized而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。这篇文章主要是从使用的角度... -
java后端面试必会技术知识点总结
2020-11-18 22:04:37HashMap是线程不安全的,在java8以前甚至可能出现由于多线程resize导致的循环链表,线程不安全的两个小例子:两个线程同时对同一桶位插入数据可能导致某个线程的数据被覆盖、某个线程在执行resize时另一线程可能读不... -
详解Java虚拟机
2021-10-28 23:22:05JAVA虚拟机 -
java初中级面试题集锦
2019-05-15 19:17:14使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变? 静态变量和实例变量的区别? 是否可以从一个 static 方法内部发出对非 static 方法的调用? "=="和 equals 方法究竟有什么区别? int和... -
并发关键字:Synchronized底层实现,锁升级原理
2022-02-18 11:29:37我们知道并发编程会产生各种问题的源头是可见性,原子性,有序性。 而synchronized能同时保证可见性,原子性,有序性。所以我们在解决并发问题的时候经常用synchronized,当然还有很多其他工具,如volatile。但是... -
深入理解Java内存模型(JMM和volatile关键词)
2019-12-25 11:35:22•Java内存模型 •内存间交互操作 •volatile型变量 •先行发生原则 •写在前面 在正式讲解之前呢,我们先来讨论讨论硬件的效率与一致性。这里我们讲讲物理机对并发的处理方案,因为物理机遇到的并发问题与...