Java中的多线程
进程:一个程序的执行
线程:程序中某个任务的流程控制
简而言之,每个独立执行的任务就是一个进程
一个正在运行的软件至少有一个进程,一个进程至少包含一个线程
进程拥有各自独立的内存空间,相对独立,而线程间可以共享数据
线程相对进程更轻量级
线程间更易进行通讯,更易切换,多线程较多进程更容易管理
线程的分类
- 普通线程(非Daemon线程)
在Java中,如果还有非Daemon线程,整个程序就不会结束 - Daemon线程(守护线程,后台线程)
如果不存在Daemon线程,则后台线程自动终止
ps:辣鸡回收线程是后台线程
线程的创建
- 方法一 通继承Thread类来创建线程
class ThreadPractice extends Thread{
@Override
public void run(){
......
......
};
}
Thread td = new Thread(){
@Override
public void run{
method(something);
}
private void method(类型 变量名){
.......
}
};
- 方法二 通过向Thread()构造方法传递Runnable对象来创建线程
class ThreadPractice implements Runnable{
public void run(){};
}
相对于Thread方式更推荐Runnable方式完成多线程操作
Thread限制了类的继承
Thread里必须使用static变量才可以共享,Runnable没有这个限制
线程的控制
-
启动
start(); -
暂停
try{
Thread.sleep(ms);
}catch(InterruptedException e){ } -
结束
- Daemon线程在无非Daemon线程时自动结束
- run执行完自动结束
- 在线程的while(true)循环中使用标记变量退出
注意
- start方法自动以新开线程的形式调用run方法,若直接调用run方法,将不会新开线程而是串行执行
- 同一个线程多次start会报错,只执行第一次的start方法
- 多个线程启动,执行顺序是由系统决定的
- main函数的线程可能早于其他线程结束
- 当所有线程终止后,程序才终止
线程安全
同时运行的线程需要共享数据,那么则需要考虑线程安全,考虑线程安全即是实现同步
如 两个线程都对一项数据进行操作,线程A取出该数据进行运算后还未更新该数据,而线程B又取出该数据一次,则某个线程的操作就被忽略了 要避免这一状况,就需要考虑线程安全
//线程不安全示例
public class ThreadSafe {
private static int cnt;
public static void main(String[] args) {
final int NUM=500;
Thread [] threads = new Thread[NUM];
for (int i=0;i<NUM;i++){
threads[i] = new Thread(){
@Override
public void run() {
int i = 0;
while(i++<1000)
cnt++;
}
};
}
for (Thread thread : threads){
thread.start();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(cnt+" "+ String.valueOf(cnt==NUM*1000));
}
}
使用synchroinzed修饰符使线程同步
在Java中,每个对象都对应于一个monitor,其中有一个成为 互斥锁(lock,muyex) 的标记,该标记用来保证任意时刻,只能有一个线程访问该对象
synchronized的用法
- 对代码片段:synchronized (对象) { }
- 对某个方法:synchronized 放在方法声明中,等价于synchronized(this),表明整个方法为同步方法
使用volatile关键字
Java的每个线程都有数据的缓存副本,存取在缓存中进行,不会立刻同步到内存中去
volatile修饰的变量一旦变化就立刻同步到内存,使得多个缓存副本保持一致
wait( )、notify( )/notifyAll( )函数控制线程
- wait释放锁,使当前线程进入等待状态
- notify唤醒等待当前对象的线程,仅唤醒一个,若有多个选项,由操作系统决定
- notifyAll唤醒所有等待该对象的线程
- notify/notifyAll未释放锁,待synchronized临界区结束后锁才释放
- 被唤醒的线程一定先处于wait状态
2018/8/11