Java:多线程基础

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

posted @ 2018-08-11 10:14  kafm  阅读(55)  评论(0编辑  收藏  举报