Java中的线程基础知识

1、线程概念

线程是程序运行的基本执行单元。当操作系统(不包括单线程的操作系统,如微软早期的DOS)在执行一个程序时,会在系统中建立一个进程,而在这个进程中,必须至少建立一个线程(这个线程被称为主线程)来作为这个程序运行的入口点。因此,在操作系统中运行的任何程序都至少有一个主线程
线程的Java抽象内存模型如下,由此可见
1)每个线程都有自己独立的工作内存
2)线程1无法访问线程2的工作内存
3)线程在访问共享数据时,会把主内存中的共享变量复制到自己的工作内存中,线程操作的是工作内存中数据的副本

2、Java中线程实现的方式

方式一:实现 Runnable 接口

class MyThread implements Runnable{ // 实现Runnable接口,作为线程的实现类private String name ; // 表示线程的名称public MyThread(String name){this.name = name ; // 通过构造方法配置name属性
}public void run(){ // 覆写run()方法,作为线程 的操作主体for(int i=0;i<10;i++){System.out.println(name + "运行,i = " + i) ;}
}
};
public class RunnableDemo01{public static void main(String args[]){MyThread mt1 = new MyThread("线程A ") ; // 实例化对象MyThread mt2 = new MyThread("线程B ") ; // 实例化对象Thread t1 = new Thread(mt1) ; // 实例化Thread类对象Thread t2 = new Thread(mt2) ; // 实例化Thread类对象t1.start() ; // 启动多线程t2.start() ; // 启动多线程}
};

方式二:继承 Thread 类

class MyThread extends Thread{ // 继承Thread类,作为线程的实现类private String name ; // 表示线程的名称public MyThread(String name){this.name = name ; // 通过构造方法配置name属性}public void run(){ // 覆写run()方法,作为线程 的操作主体for(int i=0;i<10;i++){System.out.println(name + "运行,i = " + i) ;}
}
};public class ThreadDemo02{public static void main(String args[]){MyThread mt1 = new MyThread("线程A ") ; // 实例化对象MyThread mt2 = new MyThread("线程B ") ; // 实例化对象mt1.start() ; // 调用线程主体mt2.start() ; // 调用线程主体}
};

两者的区别和联系:
1)Thread类也是Runnable接口的子类
2)Thread是类,而Runnable是接口。类和接口区别,类只能继承一次,而接口可以实现多个
3)最重要的分享资源功能,一般我们使用多线程就是快速解决资源问题。Runnable可以实现资源分享,类实现Runnable并不具备线程功能,必须通过new Thread(runabble子类)调用start()启动线程,所以我们通常new一个runnable的子类,启动多个线程解决资源问题。Thread是类所以我们每次new一个对象时候资源已经实例化了,不能资源共享,Thread类要实现资源共享,可以声明变量为static,类共享的可以解决。

3、线程状态及切换

Java中线程的状态可分为以下6种,也有归纳为5种的,但逻辑是类似的
1)初始(NEW):新创建了一个线程对象,但还没有调用start()方法
2)运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)
3)阻塞(BLOCKED):表示线程阻塞于锁
4)等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)
5)超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回
6)终止(TERMINATED):表示该线程已经执行完毕

改变线程状态的几个方法如下,
1)Thread.sleep(long millis),一定是当前线程调用此方法,当前线程进入TIMED_WAITING状态,但不释放对象锁,millis后线程自动苏醒进入就绪状态。作用:给其它线程执行机会的最佳方式
2)Thread.yield(),一定是当前线程调用此方法,当前线程放弃获取的CPU时间片,但不释放锁资源,由运行状态变为就绪状态,让OS再次选择线程。作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield()不会导致阻塞。该方法与sleep()类似,只是不能由用户指定暂停多长时间
3)thread.join()/thread.join(long millis),当前线程里调用其它线程t的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁。线程t执行完毕或者millis时间到,当前线程一般情况下进入RUNNABLE状态,也有可能进入BLOCKED状态(因为join是基于wait实现的
4)obj.wait(),当前线程调用对象的wait()方法,当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout) timeout时间到自动唤醒
5)obj.notify()唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程
6)LockSupport.park()/LockSupport.parkNanos(long nanos),LockSupport.parkUntil(long deadlines), 当前线程进入WAITING状态。对比wait方法,不需要获得锁就可以让线程进入WAITING/TIMED_WAITING状态,需要通过LockSupport.unpark(Thread thread)唤醒

4、线程优先级

最低优先级 1:Thread.MIN_PRIORITY
最高优先级 10:Thread.MAX_PRIORITY
普通优先级 5:Thread.NORM_PRIORITY
使用setPriority(Thread.MIN_PRIORITY)方法设置线程优先级。一般优先级较高的线程先执行run()方法,但是这个不是确定的。因为Java使用的是抢占式调度模型,线程的优先级具有 “随机性”,所以设置了高优先级的线程会占用更多资源,总体上会优先执行

5、线程同步

1)同步方法
用synchronized关键字修饰方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态
2)同步代码块
用synchronized关键字修饰语句块。被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
同步是一种高开销的操作,因此应该尽量减少同步的内容。通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可
3)Volatile
a.volatile关键字为域变量的访问提供了一种免锁机制
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
4)使用重入锁实现线程同步
在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力
5)ThreadLocal方式
ThreadLocal类的常用方法有如下几个:
ThreadLocal(),创建一个线程本地变量
get(),返回此线程局部变量的当前线程副本中的值
initialValue(),返回此线程局部变量的当前线程的"初始值"
set(T value),将此线程局部变量的当前线程副本中的值设置为value
ThreadLocal.ThreadLocalMap.Entry中的key是弱引用的,但是value是基于强引用的,当某个ThreadLocal对象不存在强引用时,且GC后,key会被回收,但是value还存强引用时,因此就会出现内存的泄露情况。目前最好的解决方式就是在使用完ThreadLocal及时调remove方法

6、线程安全

线程安全就是多线程访问时采用了加锁机制,当一个线程访问该类的某个数据时进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
Java中典型的非线程安全和线程安全的集合类对比如下列表。在需要考虑线程安全问题的情况下,使用线程安全的集合类实现较简单,但会影响性能,所以通常大多数的集合类是非线程安全的

非线程安全 线程安全
ArrayList Vector
HashMap HashTable
StringBuilder StringBuffer

7、线程池

主要作用

1)降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗
2)提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行
3)提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以进行统一分配、调优和监控

线程池的创建

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,   BlockingQueue workQueue,   ThreadFactory threadFactory,   RejectedExecutionHandler handler)

使用构造方法ThreadPoolExecutor(),各个参数的含义概述如下
1)corePoolSize: 线程池核心线程数最大值
2)maximumPoolSize: 线程池最大线程数大小
3)keepAliveTime: 线程池中非核心线程空闲的存活时间大小
4)unit: 线程空闲存活时间单位
5)workQueue: 存放任务的阻塞队列
6)threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题
7)handler: 线城池的饱和策略事件,主要有四种类型

调用execute方法的执行流程如下,

1)提交一个任务,线程池里存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。
2)如果线程池核心线程数已满,即线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。
3)当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。
4)如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。

几种常用的线程池

1)newFixedThreadPool (固定数目线程的线程池)
适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务
2)newCachedThreadPool(可缓存线程的线程池)
适用于并发执行大量短期的小任务
3)newSingleThreadExecutor(单线程的线程池)
适用于串行执行任务的场景,一个任务一个任务地执行
4)newScheduledThreadPool(定时及周期执行的线程池)
适用于周期性执行任务的场景,需要限制线程数量的场景

8、查看线程运行情况的命令

  1. 查看指定进程pid,以京东为例
    执行 adb shell “ps | grep jingdong”,结果如下
    u0_a415 3050 554 2707208 339720 0 0 S com.jingdong.app.mall
    u0_a415 3739 554 2274060 159168 0 0 S com.jingdong.app.mall:manto0
    u0_a415 4167 554 1895632 82336 0 0 S com.jingdong.app.mall:jdpush
    由此可知,京东app启动了三个进程,其中主进程的pid是3050
  2. 查看京东app主进程的线程运行情况
    执行 adb shell “ps -T -p 3050”,结果如下
    USER PID TID PPID VSZ RSS WCHAN ADDR S CMD
    u0_a415 3050 3050 554 2704168 339868 0 0 S ngdong.app.mall
    u0_a415 3050 3066 554 2704168 339868 0 0 S Jit thread pool
    u0_a415 3050 3067 554 2704168 339868 0 0 S Signal Catcher
    u0_a415 3050 3068 554 2704168 339868 0 0 S ADB-JDWP Connec
    u0_a415 3050 3069 554 2704168 339868 0 0 S ReferenceQueueD
    u0_a415 3050 3070 554 2704168 339868 0 0 S FinalizerDaemon

Android中的线程

1、关于应用主线程

启动应用时,系统会为该应用创建一个称为“main”(主线程)的执行线程。此线程非常重要,因为其负责将事件分派给相应的界面微件,其中包括绘图事件。此外,应用与 Android 界面工具包组件(来自 android.widget 和 android.view 软件包的组件)也几乎都在该线程中进行交互。因此,主线程有时也称为界面线程
系统不会为每个组件实例创建单独的线程。在同一进程中运行的所有组件均在界面线程中进行实例化,并且对每个组件的系统调用均由该线程进行分派。因此,响应系统回调的方法(例如,报告用户操作的 onKeyDown() 或生命周期回调方法)始终在进程的界面线程中运行

在写android界面相关代码时,需切记如下两个要点
1)不要阻塞UI线程
2)不要在UI线程之外访问Android UI工具包

2、工作线程

要保证应用界面的响应能力,关键是不能阻塞界面线程。如果执行的操作不能即时完成,则应确保它们在单独的线程(“后台”或“工作”线程)中运行
为解决此问题,Android 提供了几种途径,以便您从其他线程访问界面线程
1)Activity.runOnUiThread(Runnable)
2)View.post(Runnable)
3)View.postDelayed(Runnable, long)
4)如要通过工作线程处理更复杂的交互,可以考虑使用AsyncTask、Handler&Thread、HandlerThread、IntentService等机制实现
5) AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler,通过AsyncTask我们更加方便的执行后台任务以及在主线程中访问UI,但是AsyncTask并不适合进行特别耗时的后台任务,对于特别耗时的任务来说,建议使用线程池
6) HandlerThread继承了Thread,它是一种可以使用Handler的Thread。它的实现也很简单,就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,这样就允许在HandlerThread中创建Handler了
7) IntentService适合于执行由UI触发的后台Service任务,并可以把后台任务执行的情况通过一定的机制反馈给UI

极速版App中的线程

1、主工程中使用的线程

自定义的工作线程类NonUIThread,主要职责是按序初始化定位、加载多dex、注册推动服务等

1)在App->MyApplication类的attach阶段创建并启动的
2)通过继承Thread类的方式实现
3)通过synchronized关键字同步方法来实现单例线程类
4)默认的线程优先级是NORM_PRIORITY
5)使用obj.wait()和notify()的方式改变线程状态
6)使用setPriority(Thread.MIN_PRIORITY)方法设置线程优先级


public class MyApplication extends Application {private ProcessInitLifeCycle processInit;@Overrideprotected void attachBaseContext(Context base) {super.attachBaseContext(base);try {NonUIThread.getInstance().start();} catch (IllegalThreadStateException e) {// throws IllegalThreadStateException - if this thread has already started.// I still cannot figure out the root cause yet, just catch ite.printStackTrace();}loadMultiDex(base);//所有的需要启动初始化需要做的事情在这里执行initAppLike(base);}}public class NonUIThread extends Thread{private static final String TAG = "NonUIThread";private Handler mHandler;private final Object oLock = new Object();private final Object oIdleLock = new Object();private int previousPriority = Thread.NORM_PRIORITY;private final AtomicBoolean started = new AtomicBoolean(false);private NonUIThread(){}private static volatile NonUIThread instance;public static synchronized NonUIThread getInstance(){if(null == instance){instance = new NonUIThread();}return instance;}@Overridepublic void run() {if (started.getAndSet(true)) return;Looper.prepare();synchronized (oLock) {mHandler = new Handler();oLock.notify();}Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {@Overridepublic boolean queueIdle() {synchronized (oIdleLock){oIdleLock.notify();}return true;}});Looper.loop();}public void postRunnable(Runnable runnable){synchronized (oLock) {if(null == mHandler){try {oLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}mHandler.post(runnable);}}public void waitForIdle(){synchronized (oIdleLock){try {oIdleLock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}
}

广告弹窗业务核心类ADActvity,主要职责是负责广告弹窗的处理逻辑

1)使用AsyncTask来实现线程交互
2)调用execute()方法实际上是串行执行任务。使用executeOnExecutor(Executor)可以并行执行,但是这个api有版本限制
3)doInBackground(Params…)后台执行,比较耗时的操作都可以放在这里,注意这里不能直接操作UI
4)当前页面退出时,一般需要调用cancel()方法取消当前task,否则存在异常风险
5)AsyncTask适用于后台操作只有几秒的短时操作,否则存在内存泄露风险

public class ADActivity extends BaseActivity implements View.OnClickListener {private String homePage;private static final String AD_SHOW_TIME = "ad_show_time";private ADEntry adEntry;private int timerCount = 5;private TextView ignoreButton;private JumpEntity jumpEntity;private boolean isJumped;private Handler showTimeHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {...}};private long startTime;private AsyncTask<String, Integer, Bitmap> asyncTask = new AdDisplayTask();@Overrideprotected void onCreate(Bundle savedInstanceState) {startTime = SystemClock.elapsedRealtime();statusBarTransparentEnable = true;super.onCreate(savedInstanceState);...setContentView(R.layout.activity_a_d);...asyncTask.execute(adPath);}@Overrideprotected void onResume() {super.onResume();isJumped = false;if (showTimeHandler != null) {showTimeHandler.sendEmptyMessageDelayed(0, 1000);} else {onIgnore(null);}}@Overrideprotected void onStop() {super.onStop();finish();}@Overridepublic void finish() {if (showTimeHandler != null) {if (showTimeHandler.hasMessages(0))showTimeHandler.removeMessages(0);showTimeHandler = null;}if (asyncTask != null && !asyncTask.isCancelled()) {asyncTask.cancel(false);}super.finish();}@Overrideprotected void onDestroy() {...super.onDestroy();}@Overridepublic void onClick(View v) {onJump(v);}class AdDisplayTask extends AsyncTask<String, Integer, Bitmap> {@Overrideprotected Bitmap doInBackground(String... strings) {try {if (strings == null || strings.length == 0) return null;String path = strings[0];if (TextUtils.isEmpty(path) || !new File(path).exists()) return null;return BitmapFactory.decodeFile(path);} catch (Throwable e) {return null;}}@Overrideprotected void onPostExecute(Bitmap bitmap) {...}}
}

日志上报核心类LogReporter,主要职责是上报各页面的简单日志信息

1)使用了newFixedThreadPool线程池,长度设定为5
2)默认的线程优先级是MIN_PRIORITY,不抢占其他线程的资源
3)创建ThreadFactory创建新线程,维护线程工厂
4)有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象

public class LogReporter extends AbsLogReporter {...private ExecutorService es;LogReporter(String strategyParam) {es = Executors.newFixedThreadPool(5, new ThreadFactory(){@Overridepublic Thread newThread(@NonNull Runnable r) {Thread thread = new Thread(r);thread.setPriority(Thread.MIN_PRIORITY);return thread;}});if (!TextUtils.isEmpty(strategyParam)) {param = JDJSON.parseObject(strategyParam, LogStrategyParam.class);if (null != param) {param.parseParams();JDActivityLifeCycleCallBack callBack = JDActivityLifeCycleCallBack.getInstance();callBack.setParam(param);JdSdk.getInstance().getApplication().registerActivityLifecycleCallbacks(callBack);}}process = ProcessUtil.getProcessName(JdSdk.getInstance().getApplication());}...@Overridepublic void report(final HashMap<String, String> data) {es.execute(new Runnable() {@Overridepublic void run() {ArrayList<HashMap<String,String>> list = new ArrayList<>();list.add(data);boolean r = PerformanceReporter.reportData(list);}});}/*** report very simple msg for INNER, do not open for other package** @param msg*/void reportSimpleMessage(String msg) {HashMap<String, String> map = getAdditionalData();map.put("exceptionType", "");map.put("className", "");map.put("msg", msg);map.put("methodStack", "");map.put("occurTime", String.format("%.6f", System.currentTimeMillis() / 1000.0f));map.put("logLevel", "INNER");//private log levelmap.put("logTag", "ALC");//ActivityLifeCyclereport(map);}}

2、三方框架网络库中使用的线程

3、业务模块首页中使用的线程

1)在HomeUtil中封装了切换线程的处理逻辑
2)首页模块的各页面更新UI统一通过runOnUiThread()方法分发
3)首页模块只有PageInfoUtils类的collectCrashData()方法中直接new Thread(),但这个函数没有被调用

public class HomeUtil {public static Handler sHandler = new Handler(Looper.getMainLooper());.../*** @return 是否主线程*/public static boolean isMainThread() {return Looper.myLooper() == Looper.getMainLooper();}/*** @return 是否子线程*/public static boolean isSubThread() {return Looper.myLooper() != Looper.getMainLooper();}/*** 判断是否主线程,主线程直接执行,否则post至主线程。*/public static void runOnUiThread(BaseRun runnable) {if (isMainThread()) {runnable.run();} else {sHandler.post(runnable);}}/*** 不判断是否主线程,直接post至主线程。*/public static void postOnUiThread(BaseRun runnable) {sHandler.post(runnable);}public static void runOnUiThread(BaseRun runnable, long delayMillis) {sHandler.postDelayed(runnable, delayMillis);}...}

4、业务模块任务中心使用的线程

1)TaskFloatActivity类中的读取通讯录方法readContactList()中,通过new Thread()开启了线程
2)在线程函数中弱引用了当前的TaskFloatActivity类对象,当系统执行gc的时候该对象会被回收,读取联系的人方法buildContactsDataWithRegion()是否会抛异常待验证???
3)如果当前页面TaskFloatActivity退出了,这里通过isDestroy变量控制线程的退出,以保证后面的操作不再执行
4)建议在通讯录sdk里做修改,当TaskFloatActivity退出后,通过全局变量的方式让读取联系人的方法buildContactsDataWithRegion()快速执行完

public class TaskFloatActivity extends MvpBaseActivity<TaskCenterPresenter, BaseNavigator> implements IMissionView, PullToRefreshBase.OnRefreshListener<RecyclerView>, View.OnClickListener, MissionActiveItemView.ItemClickCallback, INewUserInterface {.../*** 获取通讯录明细*/private void readContactList() {if (isDestroy || isReading) {return;}new Thread(new Runnable() {@Overridepublic void run() {try {isReading = true;//获取通讯录listWeakReference<Activity> contextWeakReference = new WeakReference<Activity>(getThisActivity());JSONArray phoneList = ContactUtils.getPhoneList(contextWeakReference.get());if (isDestroy) {isReading = false;return;}if (null != phoneList && phoneList.length() > 0) {if (Build.VERSION.SDK_INT < 23) {//小于6.0的设备,读到证明有权限updateContactList(3, phoneList);} else {//上传ContactUtils.upload(MissionUtils.CONTACT_ACT_ID, phoneList);}} else {//通讯录为空,小于6.0的设备if (Build.VERSION.SDK_INT < 23) {post(new Runnable() {@Overridepublic void run() {showErrorDialog();}});}}isReading = false;} catch (Exception e) {isReading = false;e.printStackTrace();}}}).start();}...}

5、线程使用注意事项

1)更新UI务必在主线程,极速版使用的网络框架回调是在子线程里执行的,需要切到主线程更新UI
2)尽量减少使用new Thread()方式,使用时充分考虑线程安全问题,页面退出时要确保线程快速执行完(满足需求的前提下)
3)如果页面退出后,线程仍需要继续执行完,建议使用Service来实现
4)异步任务比较多时,应该使用线程池
5)虽然使用多线程可以提高程序的并发量,但是我们需要特别注意因为引入多线程而可能伴随而来的内存问题

Java中的线程基础知识相关推荐

  1. Java中的线程基础篇-线程基本概念

    线程的概念.创建方式.生命周期.优缺点 一.基础知识 1. 进程.线程.协程 1.1 进程 1.2 线程 1.3 协程 2. 串行.并发.并行 2.1 串行 2.2 并发 2.3 并行 二.线程的创建 ...

  2. JavaSE基础二十:Java 多线程(线程基础知识、Java 多线程、Java 实现多线程(继承 Thread 类、实现 Runnable 接口、实现 Callable 接口))

    本章目录 1.基础知识准备 2.Java 多线程概述 3.Java 实现多线程 3.1.继承 Thread 类 如何开启新线程 Thread 类常用方法 多线程中的同步 Thread 类同步方法 多线 ...

  3. Java中浮点数的基础知识

    偶然查看Math.round的JDK 1 public static int round(float a) { 2 if (a != 0x1.fffffep-2f) // greatest float ...

  4. java中的greeting_JAVA基础知识——字符串

    1.从概念上讲,JAVA字符串就死Unicode字符序列,JAVA没有内置的字符串类型,而是在标准JAVA类库中提供了一个预定义类,叫做String.字符串用""括起来 2.子串: ...

  5. java中集合的基础知识_javaSE基础知识之集合类

    集合:Collection(是接口),集合用于存储一组元素.提供了维护集合的相关操作.其派生了两个子接口: List: 可重复集 .Set:不可重复集.元素是否重复,依靠元素自身的equals方法比较 ...

  6. java中的多态有哪些_简单了解Java中多态的基础知识

    一.多态 多态分为两种:(1)引用的多态.(2)方法的多态 引用的多态: 父类的引用可以指向本类的对象: 父类的引用可以指向子类的对象: 注意:子类的对象不可以指向父类的对象,如下图所示 方法的多态: ...

  7. 青铜2:本来面目-如何认识Java中的线程

    在前面的<兵分三路:如何创建多线程>文章中,我们已经通过Thread和Runnable直观地了解如何在Java中创建一个线程,相信你已经有了一定的体感.在本篇文章中,我们将基于前面的示例代 ...

  8. Java 线程 基础知识总结

    线程基础 很不严谨的说,线程是什么?线程就是为了让很多个东西并发执行,大大的提高程序执行的效率啊 三个非常重要的概念: 程序:一组写好了的静态代码块(就我们写的那些代码玩意) 进程:正在进行着的程序, ...

  9. java线程基础知识整理

    线程基本概念 1.什么是进程?什么是线程? 进程是一个应用程序,线程是一个进程中的执行场景/执行单元.一个进程可以启动多个线程.在java语言中对于两个线程A和B,堆内存和方法区内存共享.但是栈内存独 ...

最新文章

  1. 【robotframework】robotframework基本使用
  2. Hadoop 2.x 完全分布式HA集群环境搭建
  3. sklearn中模型的选择和各个模型的比较
  4. 在线maven托管_使用Amazon s3托管您的Maven工件
  5. jdbc是java语言编写的类和接口_JDBC——Java语言连接数据库的标准
  6. 控件的事件 1124
  7. aix ip别名配置
  8. python操作linux命令行_python调用调用Linux命令
  9. 利用caffe日志进行测试精度训练损失等的画图(caffe训练结果可视化)
  10. iOS开发——源代码管理——git(分布式版本控制和集中式版本控制对比,git和SVN对比,git常用指令,搭建GitHub远程仓库,搭建oschina远程仓库 )...
  11. 迄今为止最详细的ubuntu无盘工作站安装指南
  12. angular中uibpagination里面参数配置
  13. 【分享】基于单片机家庭防盗报警系统设计-基于51单片机的智能照明控制系统-基于单片机电压控制灯光亮度报警系统-基于51单片机的公交车安全智能检测系统-基于51单片机的金属探测仪控制设计-毕设课设资料
  14. 2021-11-07 c语言之不变初心数
  15. LED办公楼宇照明节能方案及城市夜景照明节能方案
  16. 厉害!95后2万月薪程序员,背着电脑送外卖,途中还要改bug!
  17. linux服务器IP伪造,Linux服务器间同网段IP伪装端口映射
  18. HTML5开发APP页面(动效篇)
  19. 打字狗打字练习 - java关键字
  20. 美语音标 [ə]的几点注意

热门文章

  1. 关于交换两个整型变量值的几种方法
  2. java 数字转换中文_数字转换成中文 java实现
  3. 智能控制中的智能控制技术在智能安防中的应用
  4. Yoink 3.5.11 文件临时存放站
  5. 易车网全部品牌、车型、车款、价格以及4S店数据
  6. contenteditable 属性
  7. ITIL® 4 Foundation 考试知识点
  8. pid算法_pid控制原理
  9. 强化学习大牛Sergey Levine新作:三个大模型教会机器人认路
  10. 我们如何面对权利和特权