• 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

  • 相关阅读:
    Hosts文件的使用
    【java】关于时间
    【java】定时器
    log4j2的使用
    【springMVC】简单的前后端数据交流
    springMVC简单示例
    442. Find All Duplicates in an Array
    448. Find All Numbers Disappeared in an Array Add to List
    xml scheme 示例解析
    《C#高效编程》读书笔记04-使用Conditional特性而不是#if条件编译
  • 原文地址:https://www.cnblogs.com/kafm/p/12721846.html
Copyright © 2020-2023  润新知