javajava 跨域问题!

我有3个关于HashMap的问题想请大家帮忙解答一下!
HashMap桶的个数是多少?
HashMap put值的时候是怎么put的?
HashMap get值的时候是怎么get的?
![_](https://yqfile.alicdn.com/4c1f7fad97d13ac19fe0f97a7e7528.png)原文:【强制】在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。 说明:1)增加查
云服务器(Elastic Compute Service,简称 ECS)是一种简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本,使您更专注于核心业务创新。本文分为Linux系统操作运维和Windows系统
假设是一个购物系统,为了防止库存出现负的,做了个乐观锁,
就是只更新版本比数据库中的version高的,如果相同,就重新读一遍库存做判断票数够不够嘛,
但是这根直接在sql里面写,update xxx-20 where xxx-20&0 有啥区别,
一个小型网站部署到阿里云服务器图片、js加载时间很长,
![7WG_KQX_LLX1RM_VLW_AORK](https://yqfile.alicdn.com/97f70a5b405dcfc1ca02.p
如今计算机已经渗透到企业运作的各个角落,企业依靠所存放的这些业务数据进行决策,因此企业如何存放数据成为企业信息系统的重中之重,这也掀起了如今的存储热潮。根据不同的应用环境通过采取合理、安全、有效的方式将数据保存并能保证有效的访问需要更高要求的存储模式。
随着科技的飞速发展,“人工智能”无疑成为了当下最火的词。在这一领域,我们仍处于非常初级的阶段,很多事情我们还不了解。它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专
关于TreeSet集合的问题,为什么每次添加只能添加进去一个,再添加的时候就会覆盖掉前面那个不知道为什么只能添加一个对象进去,添加第二次的时候就覆盖掉了第一次添加进去的。麻烦大家了!
这是main方法
if(&a&.equalsIgnoreCas
import java.util.ArrayL
import java.util.L
public class ListTest {
public List
总体需求是实现用户注册登录写日记
我定义了一个用户类,一个用户操作类,一个日记类,在用户操作类里面申明了一个100个空间的用户对象数组,然后用户调用操作类方法完成登录注册,然后现在日记类的话也是用户调用操作类写日记方法写日记,按理应该是一个用户可以对应多个日
大神们怎么能让 serverSocket.accept()等待一段时间如果没人连接就退出啊
public List socketAccept(ServerSocket server){
long time=System.curren
问题是这样的,尝试开发一个窗体,在窗体内有两个按钮,一个start,一个stop,当点击start按钮时在控制台持续打印一句话,当用户点击stop按钮时控制台打印结束。我的源代码是这样的,不知道哪里出错了,按下start以后就按不动stop了,求大神解答!
public interface Read{
public class Student implements Read{
public class Create{
private boolean isEmpty=
public synchronized void put(int i) {
while(!this.isEmpty)
假如说`Excel`表中某一列为电话号码``,怎样提取不会让电话号码变成这个样`2.E10`
如题,在做界面的时候,把JButton上set了一个icon,就把原来的文字覆盖了,set background也是这样,怎么解决呢?
Echo e1=new Echo();
Echo e2=new Echo();
Echo e1=new Echo();
Echo e2=e1;
做EXCEL转图片时出现了一点小问题,在网上没有找到解决的拌饭,各位如果又碰到类似的,麻烦给我提示
实现的功能:使用openoffice4将excel转为PDF,然后通过PDFReaderer将PDF转为图片。
实现的思路:tomcat启动时调用openo
Java开源缓存框架介绍(OSCache,JSC)
OSCache是个一个广泛采用的高性能的J2EE缓存框架,OSCache能用于任何Java应用程序的普通的缓存解决方案。
有一个疑惑。就是JAVA缓存框架与memcache有什么区别呢?我把所有数据查已解决问题
java 问题 求解(程序正确,但是运行后什么都没有,出现下面的那些看不懂)
import java.applet.*;import java.awt.event.*;import java.awt.*;abstract class Test extends Applet implements KeyListener{
public void init()
addKeyListener(this);
requestFocus();
public void KeyTyped(KeyEvent e)
if(e.getKeyChar()=='g'||e.getKeyChar()=='G')
clr=Color.
setBackground(clr);
public void keyReleased(KeyEvent e)
public void keyPressed(KeyEvent e)
{}}为什么会出现下面的问题at sun.applet.AppletPanel.runLoader(AppletPanel.java:714) at sun.applet.AppletPanel.run(AppletPanel.java:368) at java.lang.Thread.run(Thread.java:619)
浏览次数:1639
用手机阿里扫一扫
最满意答案
改好了~import&java.applet.*;import&java.awt.event.*;import&java.awt.*;public&class&Test&extends&Applet&implements&KeyListener{&&&&&&&&&&&&Color&&&&&&&&&&&&&public&void&init()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&addKeyListener(this);&&&&&&&&&&&&&&&&requestFocus();&&&&&&&&&&&&}&&&&&&&&&&&&public&void&keyReleased(KeyEvent&e)&&&&&&&&&&&&{}&&&&&&&&&&&&public&void&keyPressed(KeyEvent&e)&&&&&&&&&&&&{}&&&&&&&&&&&&@Override&&&&&&&&&&&&public&void&keyTyped(KeyEvent&e)&{&&&&&&&&&&&&&&&&//&TODO&Auto-generated&method&stub&&&&&&&&&&&&&&&&if(e.getKeyChar()=='g'||e.getKeyChar()=='G')&&&&&&&&&&&&&&&&&&&&clr=Color.&&&&&&&&&&&&&&&&else&&&&&&&&&&&&&&&&&&&&clr=&&&&&&&&&&&&&&&&setBackground(clr);&&&&&&&&&&&&&&&&&&&&&&&&&&&&}}&1、将abstract&class改成public&class2、keyTyped第一个字母k是小写
答案创立者
以企业身份回答&
正在进行的活动
生意经不允许发广告,违者直接删除
复制问题或回答,一经发现,拉黑7天
快速解决你的电商难题
店铺优化排查提升2倍流量
擅长&nbsp 店铺优化
您可能有同感的问题
扫一扫用手机阿里看生意经
问题排行榜
当前问题的答案已经被保护,只有知县(三级)以上的用户可以编辑!写下您的建议,管理员会及时与您联络!
server is okJava 经典问题Java 经典问题科技模范百家号九种基本类型及封装类基本类型booleanbytecharshortintlongdoublevoid二进制位数18(一字节)16(2字节)16(2字节)32(4字节)64(8字节)64(8字节)--封装器类BooleanByteCharacterShortIntegerLongDoubleVoidswitch语句后的控制表达式只能是short、char、int、long整数类型和枚举类型,不能是float,double和boolean类型。String类型是java7开始支持。位运算符左移(右移(&&):int是32位,最高位是符号位,0代表正数,1代表负数,负数以补码的形式存储在计算机中。右移规则:最高位是什么(0或者1),右移的时候左边就补什么。即正数右移用0补位左边,负数右移用1补位左边。无符号右移(&&&):不管是负数还是正数,右移总是左边补0。与运算(&)或运算(|)非运算(~)异或运算(^):位相同为0,相异为1-5右移3位后结果为-1,-1的二进制为:11 11
// (用1进行补位)-5无符号右移3位后的结果
换算成二进制:11 11
// (用0进行补位)应用:不用临时变量交换两个数void swap(int argc, char *argv[]){ a = a ^ b = b ^ a = a ^}for循环,ForEach,迭代器效率直接for循环效率最高,其次是迭代器和 ForEach操作。其实 ForEach 编译成字节码之后,使用的是迭代器实现的。synchronized和volatilevolatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。volatile保证了变量的可见性,synchronized保证了原子性和可见性。volatile原理:首先我们要先意识到有这样的现象,编译器为了加快程序运行的速度,对一些变量的写操作会先在寄存器或者是CPU缓存上进行,最后才写入内存。而在这个过程,变量的新值对其他线程是不可见的,而volatile的作用就是使它修饰的变量的读写操作都必须在内存中进行。volatile告诉JVM, 它所修饰的变量不保留拷贝,直接访问主内存中的。volatile与synchronizedvolatile本质是在告诉JVM当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.volatile仅能实现变量的修改可见性,但不具备原子特性,而synchronized则可以保证变量的修改可见性和原子性。volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞。volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化。volatile不能保证原子性原因:线程A修改了变量还没结束时,另外的线程B可以看到已修改的值,而且可以修改这个变量,而不用等待A释放锁,因为Volatile 变量没上锁。注意声明为volatile的简单变量如果当前值由该变量以前的值相关,那么volatile关键字不起作用。也就是说如下的表达式都不是原子操作:n = n + 1 ;n ++ ;只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如n = m + 1。Java内存模型的抽象(volatile)在java中,所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享(本文使用“共享变量”这个术语代指实例域,静态域和数组元素)。局部变量,方法定义参数和异常处理器参数不会在线程之间共享,在栈内存中,不需要同步处理,因为栈内存是线程独享的,它们不会有内存可见性问题,也不受内存模型的影响。Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本(寄存器或CPU缓存)本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。Java内存模型的抽象示意图如下:java内存模型从上图来看,线程A与线程B之间如要通信的话,必须要经历下面2个步骤:首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。然后,线程B到主内存中去读取线程A之前已更新过的共享变量。下面通过示意图来说明这两个步骤:如上图所示,本地内存A和B有主内存中共享变量x的副本。假设初始时,这三个内存中的x值都为0。线程A在执行时,把更新后的x值(假设值为1)临时存放在自己的本地内存A中。当线程A和线程B需要通信时,线程A首先会把自己本地内存中修改后的x值刷新到主内存中,此时主内存中的x值变为了1。随后,线程B到主内存中去读取线程A更新后的x值,此时线程B的本地内存的x值也变为了。从整体来看,这两个步骤实质上是线程A在向线程B发送消息,而且这个通信过程必须要经过主内存。JMM通过控制主内存与每个线程的本地内存之间的交互,来为java程序员提供内存可见性保证。equals与==的区别==常用于比较原生类型,而equals()方法用于检查对象的相等性。另一个不同的点是:如果==和equals()用于比较对象,当两个引用地址相同,== 返回true。而equals()可以返回true或者false主要取决于重写实现。最常见的一个例子,字符串的比较,不同情况 == 和equals()返回不同的结果。看Object源码:public boolean equals(Object obj) { return (this == obj); }==表示的是比较两个对象实例的内存地址是否相同。如果不重写equal(),就和==等效,相等(相同)的对象必须具有相等的哈希码(或者散列码)。如果两个对象的hashCode相同,它们并不一定相同。术语来讲的区别:==是判断两个变量或实例是不是指向同一个内存空间。equals是判断两个变量或实例所指向的内存空间的值是不是相同。==指引用是否相同equals()指的是值是否相同hashCode作用以java.lang.Object来理解JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样:new Object(),JVM根据这个对象的Hashcode值放入到对应的Hash表对应的Key上,如果不同的对象却产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上串在一起。比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal。java.lang.Object中对hashCode的约定:在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。Object的公用方法clone 保护方法,只有实现了Cloneable接口才可以调用,否则抛异常getClassfinal方法,获得运行时类型toStringequalshashCodewait 就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait方法一直等待,直到获得锁或者被中断。wait设定一个超时间隔,如果在规定时间内没有获得锁就返回。调用该方法后当前线程进入睡眠状态,直到以下事件发生。其他线程调用了该对象的notify方法。其他线程调用了该对象的notifyAll方法。其他线程调用了interrupt中断该线程。时间间隔到了。此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。notifynotifyAllJava四种引用 --- 这里指的是“引用“,不是对象强引用平常我们使用对象的方式Object object = new Object();如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出OutOfMemoryError 错误,使程序异常终止。例如下面的代码:public class Main { public static void main(String[] args) { new Main().fun1(); } public void fun1() { Object object = new Object(); Object[] objArr = new Object[1000]; }}当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。但如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。软引用软引用通过SoftReference创建,在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收,只有在内存不足时,软引用才会被垃圾回收器回收。软引用的这种特性使得它很适合用来解决 OOM 问题,实现缓存机制,例如:图片缓存、网页缓存等等……软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。弱引用事实上软引用和弱引用非常类似,两者的区别在于:只具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,这个弱引用就会被加入到与之关联的引用队列中。虚引用虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会影响对象的生命周期。如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。强引用:不管什么时候都不会被回收。软引用:当内存不足的时候,JVM垃圾回收会回收。弱引用:不管内存足不足,只要发生JVM垃圾回收就会回收。虚引用:随时都可能会被回收。小结引用和引用队列提供了一种通知机制,允许我们知道对象已经被销毁或者即将被销毁。GC要回收一个对象的时候,如果发现该对象有软、弱、虚引用的时候,会将这些引用加入到注册的引用队列中。软引用和弱引用差别不大,JVM都是先把SoftReference和WeakReference中的referent字段值设置成null,之后加入到引用队列;而虚引用则不同,如果某个堆中的对象,只有虚引用,那么JVM会将PhantomReference加入到引用队列中,JVM不会自动将referent字段值设置成null。实际应用:利用软引用和弱引用缓存解决OOM问题。如:Bitmap的缓存设计思路是:用一个HashMap来保存图片的路径和相应图片对象(Bitmap)的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。在Android开发中对于大量图片下载会经常用到。wait()、notify()和sleep()wait()和notify()wait()和notify()是直接隶属于Object类,在JAVA中的Object类型中,都是带有一个内存锁的,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现JAVA中简单的同步、互斥操作。明白这个原理,就能理解为什么synchronized(this)与synchronized(static XXX)的区别了,synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例。wait只能由持有对像锁的线程来调用。Obj.wait()与Obj.notify()必须要与synchronized(Obj)一起使用,从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。wait():促使当前线程等待直到另外一个线程调用这个对象的notify()方法唤醒。和synchronized块使用的时候,synchronized获取对象的锁以后,可以通过wait()方法释放,同时阻塞当前线程,停止执行(这也是和sleep的区别)。public static void firstMethod(){ synchronized (a){ System.out.println(Thread.currentThread().getName() + & firstMethod--死锁&); try {// Thread.sleep(10); a.wait(); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (b){ System.out.println(Thread.currentThread().getName() + & firstMethod--解锁&); } } } public static void seconedMethod(){ synchronized (b){ System.out.println(Thread.currentThread().getName() + & seconedMethod--死锁&); synchronized (a){ System.out.println(Thread.currentThread().getName() + & seconedMethod--解锁&); a.notify(); } } }如果用两个线程分别执行这两个方法public static void main(String[] args) { Runnable runnable1 = new Runnable() { @Override public void run() { firstMethod(); } }; Runnable runnable2 = new Runnable() { @Override public void run() { seconedMethod(); } }; Thread thread1 = new Thread(runnable1); Thread thread2 = new Thread(runnable2); thread1.start(); thread2.start(); }如果是用sleep方法替换掉wait方法,就是一个死锁,线程thread1先执行拿到a对象的锁,然后阻塞10ms(并没有释放锁),thread2然后拿到对象b的锁,这时候seconedMethod需要a对象的锁,但是firstMethod并没有释放,然后10ms过后,firstMethod需要b的锁,然后b的锁也没有在seconedMethod方法中释放,两个线程相互等待对方释放锁,就形成了死锁。运行结果:Thread-0 firstMethod--死锁Thread-1 seconedMethod--死锁如果不使用sleep而是使用wait方法,就不会发生死锁。因为wait释放了firstMethod中的a对象的锁,当seconedMethod需要a对象锁的时候就可以用了。运行结果:Thread-0 firstMethod--死锁Thread-1 seconedMethod--死锁Thread-1 seconedMethod--解锁Thread-0 firstMethod--解锁notify():唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程(随机)。直到当前的线程放弃此对象上的锁,才能继续执行被唤醒的线程。sleep()通过Thread.sleep()使当前线程暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁。也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕捉异常。public class ThreadLock { Object lock = new Object(); int num = 0; public static void main(String[] args) { ThreadLock test = new ThreadLock(); Runnable runnable = new Runnable() { @Override public void run() { test.method2(); } }; Thread thread1 = new Thread(runnable); thread1.start(); test.method1(); } public void method1(){ synchronized (lock){ try { Thread.sleep(1000);// lock.wait(1000); num += 100; } catch (InterruptedException e) { e.printStackTrace(); } } } public void method2(){ synchronized (lock){ num += 9; System.out.println(num); } }}因为在main线程调用方法,因此先执行主线程的method1,对象锁被主线程拿走了,那么子线程执行method2的时候就需要等待1秒后把锁还回来。1秒后输出结果:109如果替换成lock.wait(1000);lock.wait(1000)会让当前线程(main线程)睡眠1秒,同时释放synchronized的对象锁,因此小于1秒输出9synchronized和lock几个概念共享变量(shared variable):多个线程都能访问的变量。变量可见性(variable visibility):一个线程更新了共享变量,对其他线程立刻可见。互斥(mutual exclusion ):几个线程中的任何一个不能与其他一个或多个同时操作一个变量。临界区(critical section):访问共享资源的一段代码块。synchronized保证共享变量的可见性:变量缓存与编译器指令优化会导致变量修改的不可见性。保证共享变量的互斥性:同一时刻只能有一个线程对共享变量的修改(注意修改一次,是先读再写,是两个操作)。特点:当程序运行到非静态的synchronized同步方法上时,自动获得与正在执行代码类的当前实例(this实例)有关的锁。如果两个线程要执行一个类中的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能有一个线程能够执行方法,另一个需要等待,直到锁被释放。也就是说:如果一个线程在对象上获得一个锁,就没有任何其他线程可以进入(该对象的)类中的任何一个同步方法。线程可以获得多个锁。比如,在一个对象的同步方法里面调用另外一个对象的同步方法,则获取了两个对象的同步锁。线程同步方法是通过锁来实现,每个对象都有且仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,其他访问该对象的线程就无法再访问该对象的其他同步方法。对于同步,要时刻清醒在哪个对象上同步,这是关键。死锁是线程间相互等待锁造成的。locklock提供了如下的方法:void lock(),获取一个锁,如果锁当前被其他线程获得,当前的线程将被休眠。boolean tryLock(),尝试获取一个锁,如果当前锁被其他线程持有,则返回false,不会使当前线程休眠。boolean tryLock(long timeout,TimeUnit unit),如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false。void lockInterruptibly(),如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断。synchronized和lock区别synchronized是在JVM层面上实现的,如果代码执行时出现异常,JVM会自动释放monitor锁。而lock代码是用户写的,需要用户来保证最终释放掉锁。lock提供了一个重要的方法newConditon(),ConditionObject有await()、signal()、signalAll(),类似于Ojbect类的wait()、notify()、notifyAll()。这些方法都是用来实现线程间通信。lock将synchronized的互斥性和线程间通信分离开来,一个lock可以有多个condition。另外lock的signal可以实现公平的通知,而notify是随机从锁等待队列中唤醒某个进程。性能上来说,在多线程竞争比较激烈地情况下,lock比synchronize高效得多。public class ThreadLock { public static void main(String[] args) { Test test = new Test(); Lock lock = new ReentrantLock(); Runnable runnable = new Runnable() { @Override public void run() { lock.lock(); for (int i = 0; i ReentrantLock与synchronized的比较ReentrantLocak(可重入锁)简单来说,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。ReentrantLock提供了synchronized类似的功能和内存语义。不同ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。ReentrantLock的性能比synchronized会好点。ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。缺点lock 必须在 finally 块中释放。否则,如果受保护的代码将抛出异常,锁就有可能永远得不到释放!这一点区别看起来可能没什么,但是实际上,它极为重要。忘记在 finally 块中释放锁,可能会在程序中留下一个定时炸弹,当有一天炸弹爆炸时,您要花费很大力气才能找到源头在哪。而使用同步,JVM 将确保锁会获得自动释放。当 JVM 用 synchronized 管理锁定请求和释放时,JVM 在生成线程转储时能够包括锁定信息。这些对调试非常有价值,因为它们能标识死锁或者其他异常行为的来源。 Lock 类只是普通的类,JVM 不知道具体哪个线程拥有 Lock 对象。ArrayList,LinkedList和VectorArrayList和Vector都是基于数组实现的,所以查询效率高,插入效率低。LinkedList基于双向链表实现的,所以插入效率高,查询效率低。Vector使用了synchronized方法,所以线程安全,性能比ArrayList低。LinkedList实现了List接口,还提供了额外的get,remove,insert方法在LinkedList的首部或尾部,这些操作使LinkedList可被用作栈(Stack),队列(Queue)或双向队列(deque)。ArrayList和LinkedList允许null元素,重复元素。HashMap和HashTable都实现了Map接口HashMap允许key为null,value为null而HashTable不允许,如果新加入的key和之前重复了,会覆盖之前的value。HashTable线程安全,而HashMap不是线程安全。因此单线程下HashTable比HashMap慢。HashMap不能保证随着时间推移Map中的元素次序是不变的。Hashtable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。ConcurrentHashMap锁分段技术HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,那假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。HashSet实现了Set接口,HashSet本质就是一个HashMap,把HashMap的key作为HashSet的值,HashMap的value是一个固定的Object对象,因为HashMap的key是不允许重复的,所以HashSet里的元素也是不能重复的,也可以看出HashSet的查询效率很高。String,StringBuilder和StringBufferCharSequence接口:一个字符序列。String,StringBuilder 和 StringBuffer都实现了它。String类:是常量,不可变.StringBuilder类:只可以在单线程的情况下进行修改(线程不安全),字符串拼接用,除了StringBuffer可用场景外。StringBuffer类:可以在多线程的情况下进行改变(线程安全),比如:在http请求中拼接。StringBuilder比StringBuffer效率高,应该尽量使用StringBuilder。Excption与Error包结构结构图:结构图ThrowableThrowable是 Java 语言中所有错误或异常的超类。Throwable包含两个子类: Error 和 Exception 。它们通常用于指示发生了异常情况。Throwable包含了其线程创建时线程执行堆栈的快照,它提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息。ExceptionException及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。RuntimeExceptionRuntimeException是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。编译器不会检查RuntimeException异常。 例如,除数为零时,抛出ArithmeticException异常。RuntimeException是ArithmeticException的超类。当代码发生除数为零的情况时,倘若既&没有通过throws声明抛出ArithmeticException异常&,也&没有通过try...catch...处理该异常&,也能通过编译。这就是我们所说的&编译器不会检查RuntimeException异常&!如果代码会产生RuntimeException异常,则需要通过修改代码进行避免。 例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!Error和Exception一样, Error也是Throwable的子类。 它用于指示合理的应用程序不应该试图捕获的严重问题,大多数这样的错误都是异常条件。和RuntimeException一样, 编译器也不会检查Error。Interface与abstract类的区别参数抽象类接口默认的方法实现它可以有默认的方法实现接口完全是抽象的。它根本不存在方法的实现实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现构造器抽象类可以有构造器接口不能有构造器与正常Java类的区别除了你不能实例化抽象类之外,它和普通Java类没有任何区别接口是完全不同的类型访问修饰符抽象方法可以有public、protected和default这些修饰符接口方法默认修饰符是public。你不可以使用其它修饰符。main方法抽象方法可以有main方法并且我们可以运行它接口没有main方法,因此我们不能运行它。多继承抽象类可以继承一个类和实现多个接口接口只可以继承一个或多个其它接口速度它比接口速度要快接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。添加新方法如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。如果你往接口中添加方法,那么你必须改变实现该接口的类。静态内部类和非静态内部类相同点内部类都可以用public,protected,private修饰。方法中都可以调用外部类的静态成员变量。不同点静态内部类可以声明静态和非静态成员变量,非静态内部类只能声明非静态成员变量。静态内部类可以声明静态和非静态方法,非静态内部类只能声明非静态方法。静态内部类不能调用外部类的非静态成员变量(静态方法和非静态方法都一样),非静态内部类都可以调用。泛型擦除一篇好博客泛型在JDK5以后才有的,擦除是为了兼容之前没有的使用泛型的类库和代码。如:ArrayList和ArrayList 在编译器编译的时候都变成了ArrayList。List list = new ArrayList();Map map = new HashMap();System.out.println(Arrays.toString(list.getClass().getTypeParameters()));System.out.println(Arrays.toString(map.getClass().getTypeParameters()));/* Output[E][K, V]*/我们期待的是得到泛型参数的类型,但是实际上我们只得到了一堆占位符。public class Main { public T[] makeArray() { // error: Type parameter 'T' cannot be instantiated directly return new T[5]; }}我们无法在泛型内部创建一个T类型的数组,原因也和之前一样,T仅仅是个占位符,并没有真实的类型信息,实际上,除了new表达式之外,instanceof操作和转型(会收到警告)在泛型内部都是无法使用的,而造成这个的原因就是之前讲过的编译器对类型信息进行了擦除。public class Main { private T public void set(T t) { this.t = } public T get() { } public static void main(String[] args) { Main m = new Main(); m.set(&findingsea&); String s = m.get(); System.out.println(s); }}/* Outputfindingsea*/虽然有类型擦除的存在,使得编译器在泛型内部其实完全无法知道有关T的任何信息,但是编译器可以保证重要的一点:内部一致性,也是我们放进去的是什么类型的对象,取出来还是相同类型的对象,这一点让Java的泛型起码还是有用武之地的。代码片段展现就是编译器确保了我们放在T上的类型的确是T(即便它并不知道有关T的任何类型信息)。这种确保其实做了两步工作:set()处的类型检验get()处的类型转换这两步工作也成为边界动作。public class Main { public List fillList(T t, int size) { List list = new ArrayList(); for (int i = 0; i
m = new Main(); List list = m.fillList(&findingsea&, 5); System.out.println(list.toString()); }}/* Output[findingsea, findingsea, findingsea, findingsea, findingsea]*/代码片段同样展示的是泛型的内部一致性。擦除的补偿如上看到的,但凡是涉及到确切类型信息的操作,在泛型内部都是无法共工作的。那是否有办法绕过这个问题来编程,答案就是显示地传递类型标签。public class Main { public T create(Class type) { try { return type.newInstance(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Main m = new Main(); String s = m.create(String.class); }}代码片段展示了一种用类型标签生成新对象的方法,但是这个办法很脆弱,因为这种办法要求对应的类型必须有默认构造函数,遇到Integer类型的时候就失败了,而且这个错误还不能在编译器捕获。public class Main { public T[] create(Class type) { return (T[]) Array.newInstance(type, 10); } public static void main(String[] args) { Main m = new Main(); String[] strings = m.create(String.class); }}代码片段七展示了对泛型数组的擦除补偿,本质方法还是通过显示地传递类型标签,通过Array.newInstance(type, size)来生成数组,同时也是最为推荐的在泛型内部生成数组的方法。 如果觉得对你有所帮助可以加入我的交流学习群一起学习哦 本文仅代表作者观点,不代表百度立场。系作者授权百家号发表,未经许可不得转载。科技模范百家号最近更新:简介:智能生活和前沿科技,遇见全球科技数码作者最新文章相关文章}

我要回帖

更多关于 java split 竖线 问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信