线程状态
我们首先介绍一下java中线程的几种状态,以及它们之间的转换关系。
新建状态(New) : 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
阻塞状态(Blocked) : 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
等待状态(Waiting) :通过调用Object.wait,Thread.join等,让线程等待某工作的完成。
超时等待(timed_waiting):通过 Thread.sleep,Object.wait(time), Thread.join(time)等,让线程等待某工作完成一段时间。
结束状态(TERMINATED) :线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
线程同步和协作
接下来我们介绍java中常见的多线程之间进行同步和协作的关键字和方法,以及一些使用工具类。
线程同步-synchronized关键字
采用synchronized关键字实现的同步机制叫做互斥锁机制。
每个对象都自动含有单一的锁,也叫监视器(monitor),可以分为对象锁和类锁2种。
多个线程访问同一个锁上的代码块时,仅仅只有一个线程获得访问权限,其他线程将阻塞等待那个线程的同步代码段执行完成。
对象锁锁定的是某个对象,可以防止多个线程访问该对象中被synchronized保护的代码段。
类锁锁定的是整个类(其实是类的Class对象),该类所有对象被synchronized保护的代码段都会被保护。
被对象锁锁定的方法A可以被和类锁锁定的方法B同时被访问。
public class Test {
private Object mLock = new Object();
public synchronized void doTest1 () {
}
public void doTest2 () {
synchronized (this ) {
}
}
public synchronized static void doTest3 () {
}
public void doTest4 () {
synchronized (Test.class) {
}
}
public void doTest5 (){
synchronized (mLock){
}
}
}
线程同步-Lock接口
Lock接口在jdk1.5中,包含在java.util.concurrent被引入,作为一个类而不是语法特性对线程同步提供支持。
相比synchronized关键字,功能更强大和灵活,例如可以尝试获取锁,然后失败;或者尝试获取锁一段时间,然后放弃。并且可以自定义获取锁的策略等。
如果同步过程中发生了失败,可以在finally中做清理操作。
只有在解决特殊问题时,才需要考虑显示Lock对象。
Lock lock = new ReentrantLock();
lock .lock ();
try {
}
finally {
lock .unlock();
}
一段典型的使用显示Lock接口的代码如下,注意我们需要使用try,finally关键字包裹释放锁的代码lock.unlock。已保证在任何情况下都能正确的释放锁。
线程同步-原子类
Jdk1.5中引入了一些对基本数据类型int,long等进行原子操作的类,例如AtomicLong,AtomicInteger等,我们可以使用它来替代普通的int,long类型变量,它们是线程安全的。
线程副本-ThreadLocal类
该类为目标数据在每个线程中存储了一个副本,将实际数据保存在一个以当前Thread为key,值为目标数据的map中。
因为每个线程的数据其实存储的是一个单独的副本,因此不存在线程同步的问题。
Android中的Looper就使用了该类,来为每个线程保存单独的一个Looper。
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static void prepare (boolean quitAllowed) {
if (sThreadLocal.get () != null ) {
throw new RuntimeException("Only one Looper may be created per thread" );
}
sThreadLocal.set (new Looper(quitAllowed));
}
public static @Nullable Looper myLooper () {
return sThreadLocal.get ();
}
线程协作-wait,notify,notifyAll
这3个方法属于Object类而不是Thread类,因此任何java对象都可以使用。
调用这3个方法前必须拥有此对象的锁,也就是我们需要在synchronized代码块中调用。
调用wait方法后,当前线程释放锁并休眠,直到其他线程通过该对象的notify,notifyAll唤醒它或者超时为止。如果wait过程中当前线程被打断,则抛出异常。
调用notifyAll方法,将唤醒所有在此对象上wait的线程,但它不会释放锁。因此notify语句尽量放在同步语句块的最后。
一般情况下,应使用notifyAll,已避免某些线程得不到唤醒。
public class SingleObjTest {
private Object mObj;
public synchronized void put (Object obj) throws InterruptedException {
while (mObj!=null ){
wait();
}
mObj = obj;
notifyAll();
}
public synchronized Object get () throws InterruptedException {
while (mObj==null ){
wait();
}
Object obj = mObj;
mObj = null ;
notifyAll();
return obj;
}
}
上面的代码我们借助wait和notify同步语句,实现了一个只有单个数据的生产者,消费者队列。当我们消费数据时,会一直休眠等待数据被其他线程生成出来为止;同理,我们要生成数据,必须一直休眠等待直到旧的数据被消费掉。
线程协作-Condition接口
Jdk1.5中,引入了Condition接口来替代Object类的wait,notify,notifyAll方法。
使用await替代wait,signal代替notify, signalAll代替notifyAll
Condition需要和之前线程同步时提到的Lock接口绑定。
Condition对于同一个锁,可以设置不同条件
public class SingleObjTest {
private Object mObj;
private Lock mLock = new ReentrantLock();
private Condition mPutCondition = mLock.newCondition();
private Condition mGetCondition = mLock.newCondition();
public void put (Object obj) throws InterruptedException {
mLock.lock ();
try {
while (mObj!=null ){
mPutCondition.await ();
}
mObj = obj;
mGetCondition.signalAll();
}
finally {
mLock.unlock();
}
}
public Object get () throws InterruptedException {
mLock.lock ();
try {
while (mObj == null ) {
mGetCondition.await ();
}
Object obj = mObj;
mObj = null ;
mPutCondition.signalAll();
return obj;
}
finally {
mLock.unlock();
}
}
}
这段代码的功能和之前使用wait,notify,notifyAll的代码相同,也是一个只有一个元素的生产者消费者队列,只不过我们采用了Condition接口来实现它。
我们用下面的图片来说明,为什么wait,notify语句使用时,wait条件判断一般使用while循环而不是if语句。
如图所示,我们现在产生了3个消费者线程,因为我们的mObj变量初始为空,因此这3个消费者线程,都将自己挂起。这时我们的生产者线程产生了一个数据,它会唤醒所有等待在该对象上的线程,也就是3个消费者线程,第一个获取到锁的消费者线程表现正常,然而第二个消费者获取到锁时,mObj已经被第一个消费者消费了,因此它会返回空,也就是发生了错误,这就是我们需要使用while循环判断条件的原因,使用while循环判断,第二个消费者发现mObj为空,则它会再次调用wait释放锁并陷入休眠中。
再说说我们为什么推荐使用notifyAll而不是notify呢,因为notify只是随机唤醒一个等待在该object上的线程,也就是有可能生产者唤醒的是生产者线程,而消费者线程没有被唤醒,这样会产生错误,因此我们推荐使用notifyAll唤醒所有等待线程。
而我们使用Condition接口,则可以为生产者和消费者建立起2个不同的条件,即mGetCondition和mPutCondiion,这样我们的生产者就只在mPutCondition上等待,也仅仅只唤醒消费者线程了。
线程协作-CountDownLatch类
Jdk1.5中引入的一个同步辅助类,用来同步一个或多个任务,强制它们等待其他任务执行的一组操作完成。
使用构造方法为它设置一个初始计数值,任何在该对象上调用的await方法都将被阻塞直到计数值到达0。
其他任务结束工作时,可以在该对象上调用countDown方法减少计数值。
该类被设计为只能触发一次,计数值不能重置。
public class CountDownTest {
static CountDownLatch c = new CountDownLatch(2 );
public static void main (String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run () {
try {
System.out .println("do first thing" );
Thread.sleep(1000 );
c.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run () {
try {
System.out .println("do second thing" );
Thread.sleep(2000 );
c.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out .println("wait countDown" );
c.await ();
System.out .println("count down finish" );
}
}
上面就是一小段CountDownLatch类的使用示例,主线程创建了一个计数值为2的Latch对象,并开启2个子线程执行任务,然后就等待2个子线程的任务执行完成。最后再执行自己的任务。
线程协作- CyclicBarrier类
该类同样是jdk1.5引入,用法类似于CountDownLatch类
CountDownLatch类强调的是一个或多个任务等待另一组任务完成。而CyclicBarrier类强调的是多个任务互相等待,直到所有任务都完成。
CountDownLatch只能够使用一次,而CyclicBarrier类则可以使用reset方法重新初始化。
public class CyclicBarrierTest {
static CyclicBarrier c = new CyclicBarrier(2 );
public static void main (String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run () {
try {
System.out .println("do first thing" );
Thread.sleep(1000 );
c.await ();
System.out .println("first thing finish" );
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run () {
try {
System.out .println("do second thing" );
Thread.sleep(2000 );
c.await ();
System.out .println("second thing finish" );
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
System.out .println("do main" );
}
}
上面的代码段展示了CyclicBarrier的基本用法,可以看到调用await方法的线程都会被阻塞住,直到所有线程的任务都完成为止。
生产者消费者模式和阻塞队列
下面我们来介绍多线程编程中经常使用的生产者消费者模式和阻塞队列,生产者消费者模式和阻塞队列在android的开发中都有着广泛的应用。
生产者消费者模式
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题,该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度。
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这种生产消费能力不均衡的问题,便有了生产者和消费者模式。
参照上面生产者,消费者模式的示意图,我们来说说该模式的几个优点。
解耦,如果让生产者直接调用消费者的某个方法,那 么生产者对于消费者就会耦合,将来如果消费者的代码发生变化, 可能会影响到生产者。而采用该模式各个生产者和消费者仅仅依赖于阻塞队列,而它们彼此之间没有任何依赖。
支持并发,生产者生产出数据后只需要将数据放入阻塞队列,即可继续生产下一个数据,而不需等待消费者消费,同样,消费者也仅仅是从阻塞队列中获取数据并处理。至于中间的数据同步,队列满时生产者阻塞,队列空时消费者阻塞等过程,则都由阻塞队列实现。
平衡生产消费速度,比如生产数据的速度时快时慢,缓冲区的好处就体现出来 了,当生产数据快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。
public static class BlockingQueue{
private Queue mQueue;
private final int MAX_SIZE;
private Lock mLock;
private Condition mNotEmptyCondition;
private Condition mNotFullCondition;
public BlockingQueue (int maxSize){
MAX_SIZE = maxSize;
mQueue = new ArrayDeque<>(MAX_SIZE);
mLock = new ReentrantLock();
mNotEmptyCondition = mLock.newCondition();
mNotFullCondition = mLock.newCondition();
}
public void put (E e) throws InterruptedException {
mLock.lock ();
try {
while (mQueue.size()>MAX_SIZE){
mNotFullCondition.await ();
}
mQueue.add(e);
mNotEmptyCondition.signalAll();
}
finally {
mLock.unlock();
}
}
public E take () throws InterruptedException {
mLock.lock ();
try {
while (mQueue.isEmpty()){
mNotEmptyCondition.await ();
}
E e = mQueue.poll();
mNotFullCondition.signalAll();
return e;
}finally {
mLock.unlock();
}
}
}
上面的代码使用我们之前介绍的Lock和Condition接口实现了一个生产者,消费者模式的阻塞队列,可以看到核心逻辑并不复杂,只要我们熟悉了之前介绍的线程之间协作的机制,就可以自己利用java提供的wait,nofity或者Lock,Condition实现一个生产者消费者队列。
我们这里为什么采用Lock,Condition接口而不是wait,notify呢,这就是我们之前说的Lock,Condition比wait,notify更灵活的原因。使用Lock,Condition我们可以为生产者线程和消费者线程建立不同的条件,这样消费者线程执行完成只唤醒等待的生产者线程,同样,生产者线程执行完成只唤醒等待的消费者线程。而wait,notify方法实现的话,生产者线程将会唤醒所有生产,消费者线程,不够灵活。
阻塞队列-BlockingQueue
上面我们介绍了生产者消费者模式的应用,以及我们自己如何实现一个生产者消费者模式的阻塞队列的示例。其实jdk中早就已经存在这样的轮子了,那就是BlockingQueue接口。
BlockingQueue的父接口是Queue,它定义了一个先进先出(FIFO)队列的基本操作,所有的插入操作都在队列尾部,所有的删除操作都在队列头部,这样就可以保证队列的FIFO特性了。而BlockingQueue接口则进一步定义了2组阻塞的出入队操作。各个主要的操作见下表,标记为Block的红色列表示BlockingQueue增加的阻塞操作。
抛出异常
特殊值
阻塞(Block)
超时(Block)
插入
add(E)
offer(E)
put(E)
offer(E,time,unit)
移除
remove
poll
take
poll(time,unit)
检查
element
peek
不可用
不可用
BlockingQueue接口有4个常见的实现类,大家可以根据需求选择其中的一个实现,在线程池的实现中就会根据池子类型的不同选择不同的BlockingQueue。
ArrayBlockingQueue:其构造函数必须带一个int参数来指明其大小.其所含的对象是以FIFO(先入先出)顺序排序的。
LinkedBlockingQueue:若其构造函数带一个规定大小的参数,生成的BlockingQueue有大小限制,若不带大小参数,所生成的BlockingQueue的大小由Integer.MAX_VALUE来决定.其所含的对象是以FIFO(先入先出)顺序排序的。
PriorityBlockingQueue:类似于LinkedBlockQueue,但其所含对象的排序不是FIFO,而是依据对象的自然排序顺序或者是构造函数的Comparator决定的顺序。
SynchronousQueue:特殊的BlockingQueue,对其的操作必须是放和取交替完成的,相当于阻塞队列的大小为1。
其他多线程中常用方法
leep方法,使当前线程睡眠一段时间,让其他线程有机会执行,但是它不会释放同步锁,也就是说如果有synchronized同步块,则其他线程依然不能访问其中的数据。Sleep方法可以给低优先级的线程运行机会,并且执行过程中可能抛出InterruptedException异常。
Yield方法,放弃线程自身的CPU控制权,给优先级相同或更高的线程运行机会。
Join方法,t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续执行。
线程复用
对于线程的创建和基本使用方法,想必大家都已经烂熟于心了吧,示例代码如下,创建一个Thread对象,传递一个Runnable接口,在其中书写我们需要的逻辑,最后调用start方法启动线程即可。
new Thread(new Runnable() {
@Override
public void run () {
}
}).start();
线程的基本用法固然简单,不过我们也知道,创建和销毁线程是操作系统才有的权限,并且也会带来一定的系统消耗,因此频繁的创建和销毁线程显示是不经济的,那么我们的线程是否能够重用呢,机智的你做为一个老司机,表示毫无压力,这简单,直接用线程池嘛,线程管理我们都用它,方便又快捷。示例代码如下:
Executor exec = Executors.newFixedThreadPool(3 );
exec.execute(new Runnable() {
@Override
public void run () {
}
});
线程池使用方便,大多数情况下我们使用它管理线程也已经足够,但是某些特殊的情况下,我们可能也会需要自己管理线程,因此我们还是需要知道一下如何能够达到复用线程的目的。
我们知道,一个线程被创建出来,是NEW状态,我们调用start方法后,处于Runnable(可执行)状态,等到某个时刻该线程被CPU选中,处于RUNNING状态时,会执行我们的run方法,run方法执行完成之后,线程也就会退出,进入最终的TERMINATED状态了。这样我们每执行一个任务就必须创建一个线程,重复以上过程。
那么我们有什么办法让线程不死亡呢,其实也很简单,那就是让run方法处于一个循环中,不直接结束不就好了,代码示例如下:
new Thread(new Runnable() {
@Override
public void run () {
while (未达到我们的退出条件){
}
}
}).start();
这里解决了我们线程执行完成直接退出的问题,不过看起来好像并没有作用,毕竟它只能做一件事情,而我们想要复用的线程是想要它可以持续不断的做任何事情的,那怎么办呢,这个时候我们之前学习的生产者消费者模式和阻塞队列就派上用场了。
new Thread(new Runnable() {
@Override
public void run () {
while (未达到我们的退出条件){
BlockingQueue queue = mQueue;
try {
Object obj = queue.take();
} catch (InterruptedException e) {
}
}
}
}).start();
这样该线程启动起来之后,可以根据外界给它的指令不断的执行操作,如果所有指令执行完成则陷入休眠等待。直到有新的指令到来或者需要退出为止。
这个看似简单的线程循环加上生产者消费者模式的示例,其实就是线程池的基本原理,线程池的源码我们以后分析。
另外该示例其实还展示了绝大多数的操作系统的运行原理,我们可以把它叫做信息机制,android,window等现代操作系统的运行都建立在信息机制的基础上。
比如android系统的主线程同样是一个信息循环加上信息队列,我们可以看一下android主线程所在的类ActivityThread的main方法中,利用android的handler,Looper,MessageQueue机制,同样建立了信息循环和信息队列。虽然不是使用java的阻塞队列,而是android自己的一套机制,但是原理上还是使用了一个循环的线程加上生产者消费者模式建立了整个android的运行环境。
public static void main (String[] args) {
Looper.prepareMainLooper();
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited" );
}
这里的生产者是各个系统服务,例如ams要求启动停止活动,WMS要求调整和重绘窗口,IMS传回的各种输入事件,都通过信息队列交给android应用程序主线程处理,另外主线程自身也会向队列中插入一些事件,以便自己之后处理。而消费者就是主线程本身,它会循环从信息队列中接收信息,进行处理。这是整个android系统运行的源泉。
interrupt方法和线程退出
上面我们学习了线程复用的方法,现在我们在来学习一下如何安全的退出线程,停止线程的stop方法因为不安全所以被废弃了,java也强烈不推荐使用,因此我们不考虑它的使用。
那么我们应该怎样终止一个正在运行中的线程呢,一般我们会使用interrupt方法,让我们来看看interrupt方法的究竟在干什么,这个方法在这4种状态下,分别有不同的表现
线程没有阻塞,则线程线程的中断状态(interrupted status) 会被置位。我们可以通过Thread.currentThread().isInterrupted() 来检查这个布尔型的中断状态。
如果线程堵塞在object.wait,Thread.join和Thread.sleep方法,将会抛出InterruptedException,同时清除线程的中断状态。
如果线程堵塞在java.nio.channels.InterruptibleChannel的IO上,Channel将会被关闭,线程被置为中断状态,并抛出java.nio.channels.ClosedByInterruptException。
如果线程堵塞在java.nio.channels.Selector上,线程被置为中断状态,select方法会马上返回,类似调用wakeup的效果。
我们没有办法强制终止一个正在运行中的线程,也不推荐这么做。我们一般调用方法建议线程结束自身,至于线程是否结束,以及怎样结束,由线程自身处理。注意interrupt方法并不具备任何强制结束线程的能力,下面是一个退出线程的示例。主要用到了interrupt方法和isInterrupted方法。
我们使用Thread.currentThread.isInterrupted在while循环中判断线程是否被中断,如果被中断就直接退出,这对应我们上面说的interrupt方法调用时,线程不阻塞的情况。
如果线程在被外部调用interrupt方法时被阻塞在wait或者sleep等方法时,那么就会发生InterruptedException,这个时候我们捕获该异常,可以在这里退出线程循环。
注意,如果我们的线程正在执行一个耗时的计算或者一个从网络或者IO读写数据的费时操作,这时线程外部调用interrupt方法,并不能终止这个耗时操作,线程会继续运行直到该耗时操作完成才推出循环。
Thread thread = new Thread(new Runnable() {
@Override
public void run () {
while (Thread.currentThread().isInterrupted() && 其他条件){
try {
} catch (InterruptedException e) {
}
}
}
}).start();
thread.interrupt();
你可能感兴趣的:(java基础)
Java基础知识
阿杰同学
JAVA基础知识 JVM java面试宝典 java 开发语言 后端
1.Java基本功1.1.Java入门(基础概念与常识)1.1.1.Java语言有哪些特点?1.1.2.关于JVMJDK和JRE最详细通俗的解答1.1.2.1.JVM1.1.2.2.JDK和JRE
【Java基础-44.7】Java 中的 Map 集合接口:实现类、继承关系及常用方法详解
AllenBright
# Java基础 java 开发语言
在Java中,Map是一种非常重要的集合接口,用于存储键值对(Key-ValuePair)。它提供了高效的键值查找和操作能力,广泛应用于各种场景中。本文将深入探讨Map接口的实现类、继承关系以及常用方法,帮助读者更好地理解和使用Map。1.Map接口概述Map是Java集合框架中的一员,位于java.util包中。它表示一组键值对的集合,其中每个键(Key)都是唯一的,而值(Value)可以重复。
Java基础——equals和hashcode
mikey棒棒棒
java 开发语言 HashSet equals hashcode 哈希表 哈希冲突
目录equals和hashCode的关系哈希表的工作原理为什么equals和hashCode必须保持一致性?HashSetHashSet的基本工作原理hashCode和equals如何协作哈希冲突为什么会发生哈希冲突?如何处理哈希冲突?哈希冲突的影响如何降低哈希冲突的发生总结equals和hashCode的关系基本规则:如果两个对象根据equals方法被认为是相等的,那么它们的hashCode值必
java基础语法学习day04---初学者必看详解
A 小码农
零基础Java语法学习体系 算法 java 后端
java基础语法学习day04---初学者必看详解分支结构什么是分支结构1、if语句1.1if语句的执行逻辑1.2if语句流程图1.3if语句用于处理分支逻辑1.4if语句不要省略{}2、ifelse语句2.1if-else语句的执行逻辑2.2if-else语句流程图2.3if-else语句处理分支逻辑练习:分支结构超市收银柜台收款程序V1.0编写一个超市收银柜台收款程序,根据商品单价、购买数量以
Java笔记——Java基础概念_java概念
啊健的影子
java 笔记 python
Java基础概念基础概念Java语言一种面向对象的语言publicclassHello{publicstaticvoidmain(String[]args){System.out.println("Helloworld!");}}publicclassHello{publicstaticvoidmain(String[]args){System.out.println("Helloworld!")
Java基础算法题
Eugene__Chen
算法 数据结构
简介实现一些基本的算法,你可以不看,但是不能不会,算法小白可以跟着一起练习。二分查找题目1:查找目标值的第一个出现位置要求:给定一个升序数组nums和目标值target,返回target第一次出现的索引,若不存在返回-1。示例:输入:nums=[1,2,2,2,3],target=2→输出:1输入:nums=[5,7,7,8,8,10],target=6→输出:-1答案:publicintfirs
月薪30k 的Java面试题,哭着也要背完!(附答案)
spring架构师1776
java jvm 面试 spring 架构
最近整理了一份面试题,只要你能好好地背,找工作就妥妥的稳。话不多说,请看题。注意:文章有点长。Java基础Java语言有哪些特点面向对象和面向过程的区别面向对象编程三大特性八种基本数据类型的大小,以及他们的封装类说说你对JDK、JRE、JVM的理解说说标识符的命名规则熟悉instanceof关键字的作用吗?说说Java自动装箱与拆箱说说重载和重写的区别Integera=127与Integerb=1
java基础笔记(工具)
GGJOB
JAVA java 笔记 开发语言
一、final的使用场景final关键字主要用于定义常量、限制继承以及防止方法重写,其具体应用场景包括:修饰变量常量:将变量声明为final后,该变量一旦初始化后就不能再改变。常见用法是定义全局常量,例如:publicstaticfinalintMAX_CONNECTIONS=100;局部变量:在方法中,将局部变量声明为final可以确保其值在赋值之后不再改变,有助于编写更安全和易于维护的代码。修
Java 高频面试闯关秘籍
向画
java 前端 面试 开发语言 职场和发展
目录Java基础篇:涵盖OOP、多线程、集合等基础知识。Java高级篇:深入探讨HashMap、JVM、线程池等高级特性。Java框架篇:介绍Spring、SpringMVC、MyBatis等常用框架。Mysql数据库篇:包含SQL语句、事务、索引等数据库知识。分布式技术篇:讲解Redis、消息队列、ElasticSearch等分布式技术。项目管理工具Git篇:阐述Git的使用流程和常见命令。综合
Java 数据类型转换
大明湖的狗凯.
java python 开发语言
Java数据类型转换文章目录Java数据类型转换一、Java基础数据类型概述二、`long`与`int`类型的转换分析(一)`int`转换为`long`(二)`long`转换为`int`三、Java数据类型转换方式(一)自动类型转换(隐式转换)(二)强制类型转换(显式转换)四、数据类型转换可能出现的问题(一)数据精度丢失(二)数据范围溢出一、Java基础数据类型概述Java中的八种基本数据类型在数
Java基础知识总结(四十八)--TCP传输、TCP客户端、TCP服务端
m0_74824592
面试 学习路线 阿里巴巴 java tcp/ip 开发语言
**TCP传输:**两个端点的建立连接后会有一个传输数据的通道,这通道称为流,而且是建立在网络基础上的流,称之为socket流。该流中既有读取,也有写入。**tcp的两个端点:**一个是客户端,一个是服务端。客户端:对应的对象,Socket服务端:对应的对象,ServerSocketTCP客户端:1,建立tcp的socket服务,最好明确具体的地址和端口。这个对象在创建时,就已经可以对指定ip和端
Java 进阶二知识--重拾者AIMING
AMING20220827
Java junit java 开发语言
初级选手:Java基础知识--重拾者AIMING——【Aimin20210819】公号进阶一选手:Java进阶一知识--重拾者AIMING——【Aimin20210819】公号目录1.参数数组和参数列表,重复使用参数2.Java深浅拷贝3.Http进行Post接口json带参数自动化4.Java使用json转换xml5.创建SpringBoot步骤以及Swagger部署,并发布Linux6.使用J
Java基础学习笔记-继承
蝴蝶不愿意
Java基础学习笔记 python 开发语言
继承是面向对象的三大特性之一,继承可以解决编程中代码冗余的问题,是实现代码重用的重要手段之一。Java中只支持单继承,即每个类只能有一个直接父类。继承的语法格式如下。[访问修饰符]classextends{}>在Java中。继承通过extends关键字实现,其中SubClass称为子类,SuperClass称为父类或基类。>访问修饰符如果是public,那么该类在整个项目中可见。>若不写访问修饰符
JAVA 学习路线 学习大纲(java 进阶路线)
m0_74823292
面试 学习路线 阿里巴巴 java 学习 开发语言
一、代码管理工具1.Git版本管理+Maven工程管理2.Maven官方文档http://maven.apache.org/guides/index.html3.Git官方文档http://git-scm.com/documentation4.SpringSide4官方文档https://github.com/springside/springside4/wiki二、JAVA学习书籍《Java基础
全网最全JAVA面试八股文,终于整理完了
Java八股文
面试 java 职场和发展 开发语言 jvm
前言又到一年金三银四面试跳槽季,你准备好了吗?今天为大家整理了目前互联网出现率最高的大厂面试题,所谓八股文也就是指文章的八个部分,文体有固定格式:由破题、承题、起讲、入题、起股、中股、后股、束股八部分组成,题目一律出自四书五经中的原文。而JAVA面试八股文也就是为了考验大家的JAVA基础功底,所以强烈建议背诵全文。1、并发编程三要素?(1)原子性原子性指的是一个或者多个操作,要么全部执行并且在执行
java基础---反射
消失的dk
java java 开发语言
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。首先获取该类的字节码文件,然后使用字节码文件的方法,反向获取对象的信息反射的基本使用1.获取Class对象要使用反射,首先需要获取类的Class对象。可以通过以下方式获取://1.通过类名.c
Apache Commons Lang学习大纲
不听话的小耳朵
apache common lang apache 学习
第一阶段:基础认知(3天)库的作用与定位了解ApacheCommons项目生态掌握Lang模块的核心价值(减少重复代码、增强Java基础功能)对比JDK原生工具类与CommonsLang的优势版本特性对比(重点关注3.x版本)环境搭建Maven/Gradle依赖配置手工导入Jar包方法IDE中源码关联技巧第二阶段:核心模块精讲(3周)字符串处理专家StringUtils深度解析空值安全处理:isB
2024Java零基础自学路线(Java基础、Java高并发、MySQL、Spring、Redis、设计模式、Spring Cloud)
ekskef_sef
面试 学习路线 阿里巴巴 java spring mysql
目录一、Java基础1、Java基础3、Java8新特性4、Java集合5、Java高并发6、Java代码实例二、MySQL数据库三、SpringBoot框架(35天)四、微服务SpringCloud四、Redis中间件五、MongoDB数据库六、Netty网络编程七、23种设计模式八、Dubbo九、JavaScript零基础入门十、Vue基础知识十一、数据结构与算法大家好,我是哪吒。现在网上的学
2024最强Java面试八股文(精简、纯手打)
m0_74823021
面试 学习路线 阿里巴巴 java 面试 开发语言
2024最新最全国内大厂Java面试高频题库本小册内容涵盖:Java基础,JVM,多线程,数据库(MySQL/Redis)SSM,Dubbo,网络,MQ,Zookeeper,Netty,微服务,大数据,算法,项目,设计模式等,篇幅足足近2千页,大家面试前拿去提前刷刷,一、基础篇1.接口和抽象类的区别相似点:(1)接口和抽象类都不能被实例化(2)实现接口或继承抽象类的普通子类都必须实现这些抽象方法不
Java基础学习笔记-多态
蝴蝶不愿意
java 学习 笔记
###1.认识多态多态一词的通常含义是指呈现出多种不同的形式或形态。而在程序设计的术语中,它意味着一个特定类型的变量可以引用不同类型的对象,并且能自动地调用引用的对象的方法,也就是根据作用到的不同对象类型,响应不同的操作。####什么是多态?同类型的对象,执行同一个行为,会表现出不同的行为特征。多态的常见形式父类类型对象名称=new子类构造器;接口对象名称=new实现类构造器;###2.向上转型子
【Java基础-44.2】Java中的LinkedList:特征与方法详解
AllenBright
# Java基础 java 开发语言
在Java集合框架中,LinkedList是一个非常重要的数据结构,它实现了List和Deque接口,提供了双向链表的实现。与ArrayList不同,LinkedList在插入和删除操作上具有更高的效率,但在随机访问元素时性能较差。本文将深入探讨LinkedList的特征及其常用方法的应用。1.LinkedList的特征1.1双向链表结构LinkedList是基于双向链表实现的,每个节点(Node
DeepSeek模拟阿里面试官——java基础(面向对象)
兀行者(做个有情怀的java程序员)
deepSeek模拟面试 java 开发语言
作为一位阿里高级Java程序员面试官,我会围绕Java面向对象编程的核心概念、实际应用以及设计原则设计问题,以全面评估候选人的理解和应用能力。以下是可能的面试问题:基本概念与实现方式请解释Java中封装、继承、多态的基本概念及其在Java中的实现方式。为什么Java不支持多重继承?如何通过接口实现类似的功能?封装的应用与优势封装在Java中的主要作用是什么?能否举例说明在实际项目中如何应用封装来提
从 0 到 1 的蜕变:Java 全栈系统学习路线图
软件职业规划
java java eclipse tomcat hibernate spring maven struts
一、Java基础阶段(1-2个月)环境搭建安装JDK,配置环境变量(JAVA_HOME、Path)熟悉IDE(推荐IntelliJIDEA或Eclipse)基础语法变量、数据类型、运算符、流程控制(if/else、for、while)数组、字符串操作、方法定义与调用输入输出(Scanner、System.out)面向对象编程(OOP)类与对象、构造方法封装、继承、多态、抽象类、接口内部类、匿名类、
2020年Java面试题(3年的工作总结)
web18285482512
面试 学习路线 阿里巴巴 java 开发语言
花了几天整理的资料,自己凭经验感觉那里重要,就记住那里.今年发生新型冠状病毒感染,在我的印象里已经28天了,加油中国!!!1.mysql面试题(20道题)2.Mysql索引原理以及索引优化面试题(10道题)3.Java基础面试题(10道题)4.详细的说明:List接口,Set接口,Map接口5.HashMap的面试题(10道题)6.springboot+ssm框架面试题(40道题)7.shiro面
全网最全JAVA面试八股文,终于整理完了
马士兵
面试 java 职场和发展 spring spring boot spring cloud maven
前言又到一年金三银四面试跳槽季,你准备好了吗?今天为大家整理了目前互联网出现率最高的大厂面试题,所谓八股文也就是指文章的八个部分,文体有固定格式:由破题、承题、起讲、入题、起股、中股、后股、束股八部分组成,题目一律出自四书五经中的原文。而JAVA面试八股文也就是为了考验大家的JAVA基础功底,所以强烈建议背诵全文。1、并发编程三要素?(1)原子性原子性指的是一个或者多个操作,要么全部执行并且在执行
JAVA面试题大全(200+道题目)
马士兵
java 开发语言 java-ee spring cloud spring boot jvm spring
一、Java基础1.JDK和JRE有什么区别?jdk:javadevelopmentkitjre:javaruntimeEnvironmentjdk是面向开发人员的,是开发工具包,包括开发人员需要用到的一些类。jre是java运行时环境,包括java虚拟机等,是提供给使用java的人用的2.==和equals的区别是什么?==比较的是两个对象,包括对象的地址位,如果比较的两个对象地址位不同,值相同
2020最全的BAT大厂面试题整理改版 (2)
2401_86963927
java jvm 开发语言
一、java面试题熟练掌握java是很关键的,大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道有哪些不足,怎么改进,还有一些java有关的一些算法,设计模式等等。(一)java基础面试知识点java中==和equals和hashCode的区别int、char、long各占多少字节数int与integer的区别谈谈对java多态的理解String、StringBuffe
2021年超详细的-Android超神学习路线总结--纯干货分享(字节,阿里,腾讯大牛联合打造)(1)
2401_86963927
android 学习
10、反射(掌握)学习Android开发,首先要学习java基础知识,尤其是校招的时候非常注重基础,即使没有项目也没关系,基础一定要打好,一般笔试以及面试的第一轮,对基础的考察是比较多的。如果是小白入门,看视频是最有助于理解的,而且是学习最快的,后面再查缺补漏的时候,就看看书就好了,或者回头翻一下笔记。如果已经学过java基础的知识,也可以直接翻一遍书,复习复习即可。看视频的时候不能只听不练,建议
【Java基础-43.3】深入解析Java中StringBuilder类:高效字符串操作的终极指南
AllenBright
# Java基础 java 开发语言
在Java中,字符串是不可变的(immutable),这意味着每次对字符串进行修改(如拼接、替换等操作)时,都会创建一个新的字符串对象。对于频繁操作字符串的场景,这种方式会导致性能问题。为了解决这个问题,Java提供了StringBuilder类,它是一个可变的字符序列,能够高效地进行字符串操作。本文将详细介绍StringBuilder类的特性、常用方法以及使用场景,帮助你更好地理解和使用这个强大
Java基础学习笔记-第3章-面向对象 (上)
Echo-26
Java java java-ee intellij-idea
一、Java面向对象学习的3条主线(第3-5章面向对象(上中下))1.Java类及类的成员属性方法构造器代码块内部类2.面向对象的3大特征封装性继承性多态性(抽象性)3.其他关键字thissuperstaticfinalabstractinterfacepackageimport……二、面向过程与面向对象二者都是一种思想,面向对象是相对于面向过程而言的面向过程,强调的是功能行为,以函数为最小单位,
java封装继承多态等
麦田的设计者
java eclipse jvm c encapsulatopn
最近一段时间看了很多的视频却忘记总结了,现在只能想到什么写什么了,希望能起到一个回忆巩固的作用。
1、final关键字
译为:最终的
&
F5与集群的区别
bijian1013
weblogic 集群 F5
http请求配置不是通过集群,而是F5;集群是weblogic容器的,如果是ejb接口是通过集群。
F5同集群的差别,主要还是会话复制的问题,F5一把是分发http请求用的,因为http都是无状态的服务,无需关注会话问题,类似
LeetCode[Math] - #7 Reverse Integer
Cwind
java 题解 Math LeetCode Algorithm
原题链接:#7 Reverse Integer
要求:
按位反转输入的数字
例1: 输入 x = 123, 返回 321
例2: 输入 x = -123, 返回 -321
难度:简单
分析:
对于一般情况,首先保存输入数字的符号,然后每次取输入的末位(x%10)作为输出的高位(result = result*10 + x%10)即可。但
BufferedOutputStream
周凡杨
首先说一下这个大批量,是指有上千万的数据量。
例子:
有一张短信历史表,其数据有上千万条数据,要进行数据备份到文本文件,就是执行如下SQL然后将结果集写入到文件中!
select t.msisd
linux下模拟按键输入和鼠标
被触发
linux
查看/dev/input/eventX是什么类型的事件, cat /proc/bus/input/devices
设备有着自己特殊的按键键码,我需要将一些标准的按键,比如0-9,X-Z等模拟成标准按键,比如KEY_0,KEY-Z等,所以需要用到按键 模拟,具体方法就是操作/dev/input/event1文件,向它写入个input_event结构体就可以模拟按键的输入了。
linux/in
ContentProvider初体验
肆无忌惮_
ContentProvider
ContentProvider在安卓开发中非常重要。与Activity,Service,BroadcastReceiver并称安卓组件四大天王。
在android中的作用是用来对外共享数据。因为安卓程序的数据库文件存放在data/data/packagename里面,这里面的文件默认都是私有的,别的程序无法访问。
如果QQ游戏想访问手机QQ的帐号信息一键登录,那么就需要使用内容提供者COnte
关于Spring MVC项目(maven)中通过fileupload上传文件
843977358
mybatis spring mvc 修改头像 上传文件 upload
Spring MVC 中通过fileupload上传文件,其中项目使用maven管理。
1.上传文件首先需要的是导入相关支持jar包:commons-fileupload.jar,commons-io.jar
因为我是用的maven管理项目,所以要在pom文件中配置(每个人的jar包位置根据实际情况定)
<!-- 文件上传 start by zhangyd-c --&g
使用svnkit api,纯java操作svn,实现svn提交,更新等操作
aigo
svnkit
原文:http://blog.csdn.net/hardwin/article/details/7963318
import java.io.File;
import org.apache.log4j.Logger;
import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmateso
对比浏览器,casperjs,httpclient的Header信息
alleni123
爬虫 crawler header
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
String type=req.getParameter("type");
Enumeration es=re
java.io操作 DataInputStream和DataOutputStream基本数据流
百合不是茶
java 流
1,java中如果不保存整个对象,只保存类中的属性,那么我们可以使用本篇文章中的方法,如果要保存整个对象 先将类实例化 后面的文章将详细写到
2,DataInputStream 是java.io包中一个数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
车辆保险理赔案例
bijian1013
车险
理赔案例:
一货运车,运输公司为车辆购买了机动车商业险和交强险,也买了安全生产责任险,运输一车烟花爆竹,在行驶途中发生爆炸,出现车毁、货损、司机亡、炸死一路人、炸毁一间民宅等惨剧,针对这几种情况,该如何赔付。
赔付建议和方案:
客户所买交强险在这里不起作用,因为交强险的赔付前提是:“机动车发生道路交通意外事故”;
如果是交通意外事故引发的爆炸,则优先适用交强险条款进行赔付,不足的部分由商业
学习Spring必学的Java基础知识(5)—注解
bijian1013
java spring
文章来源:http://www.iteye.com/topic/1123823,整理在我的博客有两个目的:一个是原文确实很不错,通俗易懂,督促自已将博主的这一系列关于Spring文章都学完;另一个原因是为免原文被博主删除,在此记录,方便以后查找阅读。
有必要对
【Struts2一】Struts2 Hello World
bit1129
Hello world
Struts2 Hello World应用的基本步骤
创建Struts2的Hello World应用,包括如下几步:
1.配置web.xml
2.创建Action
3.创建struts.xml,配置Action
4.启动web server,通过浏览器访问
配置web.xml
<?xml version="1.0" encoding="
【Avro二】Avro RPC框架
bit1129
rpc
1. Avro RPC简介 1.1. RPC
RPC逻辑上分为二层,一是传输层,负责网络通信;二是协议层,将数据按照一定协议格式打包和解包
从序列化方式来看,Apache Thrift 和Google的Protocol Buffers和Avro应该是属于同一个级别的框架,都能跨语言,性能优秀,数据精简,但是Avro的动态模式(不用生成代码,而且性能很好)这个特点让人非常喜欢,比较适合R
lua set get cookie
ronin47
lua cookie
lua:
local access_token = ngx.var.cookie_SGAccessToken
if access_token then
ngx.header["Set-Cookie"] = "SGAccessToken="..access_token.."; path=/;Max-Age=3000"
end
java-打印不大于N的质数
bylijinnan
java
public class PrimeNumber {
/**
* 寻找不大于N的质数
*/
public static void main(String[] args) {
int n=100;
PrimeNumber pn=new PrimeNumber();
pn.printPrimeNumber(n);
System.out.print
Spring源码学习-PropertyPlaceholderHelper
bylijinnan
java spring
今天在看Spring 3.0.0.RELEASE的源码,发现PropertyPlaceholderHelper的一个bug
当时觉得奇怪,上网一搜,果然是个bug,不过早就有人发现了,且已经修复:
详见:
http://forum.spring.io/forum/spring-projects/container/88107-propertyplaceholderhelper-bug
[逻辑与拓扑]布尔逻辑与拓扑结构的结合会产生什么?
comsci
拓扑
如果我们已经在一个工作流的节点中嵌入了可以进行逻辑推理的代码,那么成百上千个这样的节点如果组成一个拓扑网络,而这个网络是可以自动遍历的,非线性的拓扑计算模型和节点内部的布尔逻辑处理的结合,会产生什么样的结果呢?
是否可以形成一种新的模糊语言识别和处理模型呢? 大家有兴趣可以试试,用软件搞这些有个好处,就是花钱比较少,就算不成
ITEYE 都换百度推广了
cuisuqiang
Google AdSense 百度推广 广告 外快
以前ITEYE的广告都是谷歌的Google AdSense,现在都换成百度推广了。
为什么个人博客设置里面还是Google AdSense呢?
都知道Google AdSense不好申请,这在ITEYE上也不是讨论了一两天了,强烈建议ITEYE换掉Google AdSense。至少,用一个好申请的吧。
什么时候能从ITEYE上来点外快,哪怕少点
新浪微博技术架构分析
dalan_123
新浪微博 架构
新浪微博在短短一年时间内从零发展到五千万用户,我们的基层架构也发展了几个版本。第一版就是是非常快的,我们可以非常快的实现我们的模块。我们看一下技术特点,微博这个产品从架构上来分析,它需要解决的是发表和订阅的问题。我们第一版采用的是推的消息模式,假如说我们一个明星用户他有10万个粉丝,那就是说用户发表一条微博的时候,我们把这个微博消息攒成10万份,这样就是很简单了,第一版的架构实际上就是这两行字。第
玩转ARP攻击
dcj3sjt126com
r
我写这片文章只是想让你明白深刻理解某一协议的好处。高手免看。如果有人利用这片文章所做的一切事情,盖不负责。 网上关于ARP的资料已经很多了,就不用我都说了。 用某一位高手的话来说,“我们能做的事情很多,唯一受限制的是我们的创造力和想象力”。 ARP也是如此。 以下讨论的机子有 一个要攻击的机子:10.5.4.178 硬件地址:52:54:4C:98
PHP编码规范
dcj3sjt126com
编码规范
一、文件格式
1. 对于只含有 php 代码的文件,我们将在文件结尾处忽略掉 "?>" 。这是为了防止多余的空格或者其它字符影响到代码。例如:<?php$foo = 'foo';2. 缩进应该能够反映出代码的逻辑结果,尽量使用四个空格,禁止使用制表符TAB,因为这样能够保证有跨客户端编程器软件的灵活性。例
linux 脱机管理(nohup)
eksliang
linux nohup nohup
脱机管理 nohup
转载请出自出处:http://eksliang.iteye.com/blog/2166699
nohup可以让你在脱机或者注销系统后,还能够让工作继续进行。他的语法如下
nohup [命令与参数] --在终端机前台工作
nohup [命令与参数] & --在终端机后台工作
但是这个命令需要注意的是,nohup并不支持bash的内置命令,所
BusinessObjects Enterprise Java SDK
greemranqq
java BO SAP Crystal Reports
最近项目用到oracle_ADF 从SAP/BO 上调用 水晶报表,资料比较少,我做一个简单的分享,给和我一样的新手 提供更多的便利。
首先,我是尝试用JAVA JSP 去访问的。
官方API:http://devlibrary.businessobjects.com/BusinessObjectsxi/en/en/BOE_SDK/boesdk_ja
系统负载剧变下的管控策略
iamzhongyong
高并发
假如目前的系统有100台机器,能够支撑每天1亿的点击量(这个就简单比喻一下),然后系统流量剧变了要,我如何应对,系统有那些策略可以处理,这里总结了一下之前的一些做法。
1、水平扩展
这个最容易理解,加机器,这样的话对于系统刚刚开始的伸缩性设计要求比较高,能够非常灵活的添加机器,来应对流量的变化。
2、系统分组
假如系统服务的业务不同,有优先级高的,有优先级低的,那就让不同的业务调用提前分组
BitTorrent DHT 协议中文翻译
justjavac
bit
前言
做了一个磁力链接和BT种子的搜索引擎 {Magnet & Torrent},因此把 DHT 协议重新看了一遍。
BEP: 5Title: DHT ProtocolVersion: 3dec52cb3ae103ce22358e3894b31cad47a6f22bLast-Modified: Tue Apr 2 16:51:45 2013 -070
Ubuntu下Java环境的搭建
macroli
java 工作 ubuntu
配置命令:
$sudo apt-get install ubuntu-restricted-extras
再运行如下命令:
$sudo apt-get install sun-java6-jdk
待安装完毕后选择默认Java.
$sudo update- alternatives --config java
安装过程提示选择,输入“2”即可,然后按回车键确定。
js字符串转日期(兼容IE所有版本)
qiaolevip
TO Date String IE
/**
* 字符串转时间(yyyy-MM-dd HH:mm:ss)
* result (分钟)
*/
stringToDate : function(fDate){
var fullDate = fDate.split(" ")[0].split("-");
var fullTime = fDate.split("
【数据挖掘学习】关联规则算法Apriori的学习与SQL简单实现购物篮分析
superlxw1234
sql 数据挖掘 关联规则
关联规则挖掘用于寻找给定数据集中项之间的有趣的关联或相关关系。
关联规则揭示了数据项间的未知的依赖关系,根据所挖掘的关联关系,可以从一个数据对象的信息来推断另一个数据对象的信息。
例如购物篮分析。牛奶 ⇒ 面包 [支持度:3%,置信度:40%] 支持度3%:意味3%顾客同时购买牛奶和面包。 置信度40%:意味购买牛奶的顾客40%也购买面包。 规则的支持度和置信度是两个规则兴
Spring 5.0 的系统需求,期待你的反馈
wiselyman
spring
Spring 5.0将在2016年发布。Spring5.0将支持JDK 9。
Spring 5.0的特性计划还在工作中,请保持关注,所以作者希望从使用者得到关于Spring 5.0系统需求方面的反馈。