• Java中的多线程


    1,创建线程
    ··· 继承Thread类:
        必须覆写Thread的run方法。
    ··· 实现Runnable接口:
        必须实现run方法,再传入到Thread(Runnable t)构造方法中。
    ··· 实现Callable接口:
          class A implements Callables<String>{}
        (1)实现类A 必须实现Callable的call方法,并创建A类的对象。a = new A();
        (2)将类A的对象a作为构造方法参数创建  FutureTask对象。ft = new FutureTask<>(a);
        (3)将 ft作为构造方法参数创建 Thread对象。t = new Thread(ft);
        (4)运行线程。 t.start();
        (5)获取执行结果。 res = ft.get();
        返回数据较少使用Callable,较多使用Runnable加消息队列。
     
    2,线程
    ··· 常用实例方法:
        启动:start();   // 只可以调用一次;
        设置优先级:setPriority(int);  // 范围从1~10,默认是5,操作系统对优先级高的线程调度更频繁;
    ··· 线程的状态:
        New:新创建的线程,尚未执行;
        Runnable:运行中的线程,正在执行run()方法的Java代码;
        Blocked:运行中的线程,因为某些操作被阻塞而挂起;
        Waiting:运行中的线程,因为某些操作在等待中;
        Timed Waiting:运行中的线程,因为执行sleep()方法正在计时等待;
        Terminated:线程已终止,因为run()方法执行完毕。
        还有一种是5种状态:
        new,Runnable,run,block,deal
    ··· 线程中断:
        概念:线程A向线程B发送终止信号。
        方式一:线程A调用 b.interrupt()向线程B发送“中断请求”,而线程B的run方法中要时刻检测isInterrupted()
        方式二:设置标志位,标志位要使用共享变量(用volatile修饰)。
    ··· 守护线程:
        一种无限循环的线程,例如,一个定时触发任务的线程。
        概念:守护线程是为其他线程服务的线程,当所有非守护线程退出时,JVM退出。
        注意:守护线程不能持有需要关闭的资源(如打开文件)。
     
    3,线程同步
    ··· 使用synchronized加锁:
        对代码同步:synchronized(lock){...};只有获取了lock才会执行{...}中的代码。
        对方法同步:synchronized void func();实例方法锁住的是this,静态方法锁住的是 类.class。
    ··· 解决死锁:当多线程同时使用多个锁时,线程获取锁的顺序要一致。
    ··· 生产者消费者模型:使用 lock.wait();使线程变为等待状态线程。lock.notifyAll();唤醒等待的线程。
    ··· 注意:
        · 用类作为同步监视器时这个类所创建的对象也会共享类的锁,但是不影响this锁。
        · synchronized是可重入锁,要注意加锁的个数。
     
    4,锁
    ··· synchronized:
        对象锁,在使用synchronized同步时,可以用任意对象作为锁。
        缺点:一是比较笨重,二是获取时必须一直等待,没有额外的尝试机制。
    ···  ReentrantLock:
        可重入锁,与synchronized类似,但是比它更安全。可以用Condition来实现类似的wait和notify。
        优点:可以尝试获取锁,如果一定时间后还没有获得锁,就可以做一些额外处理,而不是一直等下去,lock.tryLock(1, TimeUnit.SECONDS)尝试去获取锁,如果1秒后还没获取到就执行其他操作。
        缺点:过于保护,对于只读取不修改数据的线程时,也会加锁,但其实是可以允许多个线程同时读的。如果对读不加锁,假如读的是一个长度为10的列表,当读到5时,如果时间片用完了;切换到修改线程,把2和8的数据被修改了。然后读线程继续读,将会读到2没有修改,而8被修改了的脏数据。
    ··· ReadWriteLock:
        读写锁,可以把读和写分离。
        优点:对于大量读取,少量修改的数据,可以大大提高并发,允许同时读。
        缺点:是一个悲观锁(针对读锁),即在读的时候不允许写。
    ··· StampedLock:
        读写锁的改进。
        优点:是一个乐观锁(针对读锁),在读的时候允许写,读完后通过版本判断是否修改了,如果修改了则再读一次。
        缺点:代码更加复杂,是不可重入锁。
    ··· 注意:
        · 如果每次访问的冲突概率小于20%,则使用乐观锁,否则使用悲观锁,乐观锁的重试次数不得小于3次。
     
    5, Concurrent集合
    ··· 概念:是Java标准库java.util.concurrent提供的线程安全的集合。
    ··· 对应的非线程安全的集合:
     
     
    6,线程池的线程数设置:
    ··· 项目中尽量使用线程池,不要显示创建线程。因为创建和销毁线程很消耗性能。
    1、CPU密集型:CPU核数 + 1;
    2、IO密集型:CPU核数 * 2;
    3、互联网IO:CPU核数 / (1 - 柱塞系数);例如阻塞系数0.8,CPU核数4,则设置线程数为 20。
     
    注意事项
        · 上下文对象:定义:在一个线程中,横跨若干方法调用,需要传递的对象叫做上下文,他是一种状态。ThreadLocal可以在一个线程中传递同一个对象。
        · 线程中的yield方法:让出当前线程的CPU执行权。在数据库插入时调用,防止数据库假死。
  • 相关阅读:
    繁简转换OpenCC,autogb 和 autob5,iconv,python的jianfan包
    Linux常用的系统监控shell脚本
    linux系统CPU,内存,磁盘,网络流量监控脚本
    linux系统巡检脚本shell实例
    主流脚本语言的比较和选择
    老男孩python第六期
    如何从 0 开始学 ruby on rails (漫步版)
    C#数学运算表达式解释器
    算法导论 第9章 中位数和顺序统计学(线性时间选择算法)
    ruby语言仅仅是昙花一现
  • 原文地址:https://www.cnblogs.com/shendeng23/p/12459653.html
Copyright © 2020-2023  润新知