zoukankan      html  css  js  c++  java
  • Java 线程应用

    一旦线程启动,它就永远不能再重新启动。只有一个新的线程可以被启动,并且只能一次。//否则报:java.lang.IllegalThreadStateException

    一系列线程以某种顺序启动并不意味着将按该顺序执行。对于任何一组启动的线程来说,调度程序不能保证其执行次序,持续时间也无法保证。

          队列形式是指当一个线程完成“一轮”时,它移到可运行队列的尾部等待,直到它最终排队到该队列的前端为止,它才能被再次选中。

          尽管我们没有无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。

    //线程创建方式:两种

    1:Thread类衍生创建

    2:实现Runnable()接口

    //注意单线程 && 多线程 的执行顺序可控



    每个线程的数据区是独立的。

    线程传参:尽可能使用 final 修饰。【线程安全】{注意:final修饰的值往往是固定的, 但是不要带变量!}




    redis:缓存、消息中间件

    MQ:消息中间件【看系统的吞吐量】

    Hadoop:选举机制

    【中间件:独立于系统之外】

    多线程情况下,会出现什么问题:

    1.对旧值不可见,从而造成数据的重复、延迟、滞后。

    synchronized 线程同步、同步锁!

    ---同步代码块、同步方法

    ---1.线程持锁,其他线程进入对象锁阻塞状态

    ---2.synchronized代码执行完毕后,其他线程开始竞争持锁。

    线程调度

    线程是不可控的,那么如何干预线程的执行?

    1.等待:让某个线程进入等待状态,等到条件满足后,被其他线程唤醒。

    this.wait();一直等待下去

    this.wait(3000);//等待3S后,如果3s内未被唤醒,3s后自动结束【结束后,争夺锁资源】

    2.休眠:是让当前线程进入休眠状态,这是Thread的静态方法,休眠只能自己醒!

    【1】本质:至少休眠指定时间。休眠之后,等待资源分配!

    【2】休眠不可以被唤醒!

    3.让步【让线程从 运行状态回到就绪状态】

    线程优先级1~10;默认为5;

    【多线程调度应用最好不要依赖于线程的优先级】——可做为一种提高程序效率的方法。【不可依赖!】

    yield——【让相同优先级的线程之间能适当的轮转执行】

    【让步没有经过阻塞,直接回到就绪状态】

    4.合并【让并行的线程,变为串行线程】

    t1.start();t1.join();t2.start();

    [先执行再合并]

    ------------------------------------------------------------------------------------------------

    什么情况要合并线程?

    【某个线程要等到前一个线程的结果时,需要合并,方便来等待前面的结果】

    ex:支付、秒杀

    MQ:异步通知。


    5.守护线程【GC:垃圾回收】

    t1.start();//用户线程

    t2.setDaemon(true);//设置为守护线程

    t2.start();


    线程同步:

    同步方法:保护整个方法当中所有数据的安全。

    同步代码块:保护方法中某个区域的数据安全。【让那些不需要考虑到同步的数据先执行,提高效率】

    一般来说:属于线程本身数据区的数据和读的数据,不影响。


    同步:只能同步方法,而不能同步变量和类。

    同一个类可以同时拥有同步和非同步方法。

    多个线程共用同一个实例的时候,同步生效。

    ---wait()    notiryall()

    线程休眠不释放资源。

    同一个线程可以获得多个锁。


    静态方法同步

    非静态同步,锁时对象锁,只有相同实例才存在哦同步

    静态同步,锁的时类。只要时这个类,就会触发同步!

    静态的锁:类。


    不建议:同时使用 静态和非静态锁!

    同步静态锁:

    public static synchronized int test();

    public void test(){

    synchronized(D.class);

    }

    非同步静态锁:

    publci synchronized int test();

    public void test1(){

    C c= new C();

    synchronized(c);

    }

    //考虑阻塞,一定要考虑锁那个对象!


    image

    【等待需要在同步环境中,不持锁,报错!——对应上图】

    线程同步和锁机制

    1.线程安全类

    集合:Collections

    List<String> list = Collections.synchronizedList(Arrays.asList(new String[] {"hello","world"}));
             list.contains("tesst");

    流的:ByteArrayInputStream

    FileInputStream fStream = new FileInputStream(new File(""));
             byte[] bytes = new byte[fStream.available()];
             fStream.read(bytes);
             ByteArrayInputStream bStream = new ByteArrayInputStream(bytes);
             bStream.read();

    StringBufferStringBuilder

    注意:

    即便是操作的线程安全类,安全仅仅局限于:对该类本身的操作。并不意味着操作其他变量也一定安全。

    【整个操作流程安全才是封装好的】


    2.死锁:两个线程持有对方的锁,且互相等待。

    【概率很小,但是无论代码中发生死锁的概率有多小,一旦发生死锁,程序就死掉了!】

    避免死锁的策略:按照相同的顺序获取锁,并释放锁。


    锁的特性:

    1.互斥:

    2.可见性



    线程同步:为了保护多个线程访问一个资源时对资源的破坏。

    实现方法:线程一旦获取对象锁,其他访问该对象的线程就无法获得该对象的其他同步方法。【即进入阻塞状态】

    而:对于静态同步方法,锁是针对该类,静态与非静态方法的锁互不干预。

    原子化:【与事务的原子性一致】

    ex: volatile变量

    1.不能用作线程计数器。

    2.只能保障独立线程安全问题。

    常见模式:

    【1】状态标志:布尔状态标志。

    【2】一次性安全发布:单例、静态【final变量不支持,因为 fanal变量是禁止修改的,也不存在线程安全的问题】

    【3】独立观察,定期发布。——一写多读

    【4】volatile bean 模式,适用于 JavaBean。【实体类:getter、setter方法】??

    [5]开销较低的读-写策略



    Volatile应用案例




    线程整体研究深入——时间问题!(基础研究问题)

    1:线程池,对象池的思想。

    本质:对象池,在其中放入若干未死亡的线程,等到必要的时候,再调用start()。

    //java.util.concurrent包下:

    线程池中:execute(Runnable 对象),即:通过Thread类实现的线程,也是实现Runnable接口!

    2:线程状态:运行状态、等待状态。

    (1)归池:尽量减少对象生成。

    MyThread treadThread = new MyThread();
             pool.execute(treadThread);
             pool.execute(treadThread);pool.execute(treadThread);pool.execute(treadThread);
             pool.execute(treadThread);pool.execute(treadThread);


    【1】固定尺寸的线程池

    //核心线程个数:每一次并发的线程最大个数。当该线程死亡后,会生成一个新的线程。

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public class ExecutorServiceDemo {
         public static void main(String[] args) {
             ExecutorService pool = Executors.newFixedThreadPool(3);
             pool.execute(new MyThread());
             pool.execute(new MyThread());
             pool.execute(new MyThread());
             pool.execute(new MyThread());
             pool.execute(new MyThread());
             pool.execute(new MyThread());
         }
    }

    class MyThread implements Runnable{
         public void run() {
             // TODO Auto-generated method stub
             try {
                 System.out.println(Thread.currentThread().getName());
                 Thread.sleep(3000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
    }

    //

    shutdown():当线程池调用后,会关闭!否则,会持续往该线程池当中添加新的线程。


    【2】单任务线程池

    //一次只执行一次,并且:该线程池当中,只有一个线程。

    //用完以后归池

    ExecutorService pool = Executors.newSingleThreadExecutor();



    【3】可变尺寸连接池

    ExecutorService pool = Executors.newCachedThreadPool();


    //上述三个归结为一类!

    【4】延迟连接池

    ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

    pool.execute(treadThread);

    pool.execute(treadThread);

    //延迟的线程不会阻塞当前队列池中的其他线程的执行。

    pool.schedule(treadThread, 5000, TimeUnit.MILLISECONDS);

    【5】单任务延迟连接池

    ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();

    pool.execute(treadThread);

    pool.execute(treadThread);

    //同样支持:延迟

    pool.schedule(treadThread, 5000, TimeUnit.MILLISECONDS);


    【6】自定义线程池【均继承于 ThreadPoolExecutor类】

    所有的线程池,都是使用自定义线程池实现的。

    如果核心数满了,则加入队列;如果队列满了,没达到上限,则新建线程。

    corePoolSize:【核心线程数:关心不是那个线程是核心,而是线程数量,没有哪个线程是核心】

    maximumPoolSize:【】

    workQueue

    //实现:

    BlockingQueue<Runnable> bQueue = new ArrayBlockingQueue<Runnable>(2);//归池操作
    ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 4, 0, TimeUnit.MICROSECONDS, bQueue);

    //

    耗时线程:pool-1-thread-1
    pool-1-thread-4
    pool-1-thread-3
    耗时线程:pool-1-thread-2
    pool-1-thread-3
    pool-1-thread-4

    //


    public class MyPoolService {
         public static void main(String[] args) {
             BlockingQueue<Runnable> bQueue = new ArrayBlockingQueue<Runnable>(2);
             ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 4, 0, TimeUnit.MICROSECONDS, bQueue);
             MyThread3 myThread3 = new MyThread3();
             MyThread3 myThread31 = new MyThread3();
             MyThread4 myThread4 = new MyThread4();
             MyThread5 myThread5 = new MyThread5();
            
             pool.execute(myThread3);
             pool.execute(myThread31);
            
             pool.execute(myThread4);
             pool.execute(myThread4);
            
             pool.execute(myThread5);
             pool.execute(myThread5);
            
         }
    }

    class MyThread3 implements Runnable{
         public void run() {
             // TODO Auto-generated method stub
             try {
                 System.out.println("耗时线程:"+Thread.currentThread().getName());
                 Thread.sleep(5000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
    }

    class MyThread4 implements Runnable{
         public void run() {
             // TODO Auto-generated method stub
             try {
                 System.out.println(Thread.currentThread().getName());
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
    }

    class MyThread5 implements Runnable{
         public void run() {
             // TODO Auto-generated method stub
             try {
                 System.out.println(Thread.currentThread().getName());
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
    }


    串行线程【解决依赖】&&&并行线程【多线程节约资源】



    比如:

    2:异步【线程的消息系统】

    锁、信号量和阻塞

    //加锁  XX   解锁

    public class MyLock {
         public static void main(String[] args) throws Exception{
             MyThread8 thread = new MyThread8();
             Thread thread2 = new Thread(thread);
             thread2.start();
         }
    }

    class MyThread8 implements Runnable{
         Lock lock = new ReentrantLock();
         public void run() {
             // TODO Auto-generated method stub
             System.out.println("加锁");
             lock.lock();
             try {
                 System.out.println(Thread.currentThread().getName());
                 Thread.sleep(3000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             lock.unlock();
             System.out.println("解锁");
         }
    }

    //重入锁、读写锁

    【对共享资源有读和写的操作,且写操作没有读操作这么频繁】

    ——1.如果没有写,其他都可读

    ——2.如果有写,其他线程不支持读和写

    //实现

    public class MyReadWriteLock2 {
         public static void main(String[] args) throws Exception{
             A a = new A();
             new Thread(new MyThread12(a)).start();
             new Thread(new MyThread11(a)).start();
             new Thread(new MyThread11(a)).start();
             new Thread(new MyThread11(a)).start();
         }
    }

    class MyThread11 implements Runnable{
         private final A a;
         public MyThread11(final A a) {
             this.a = a;
         }
         public void run() {
             a.read();
         }
    }

    class MyThread12 implements Runnable{
         private final A a;
         public MyThread12(final A a) {
             this.a = a;
         }
         public void run() {
             a.write();
         }
    }

    class A {
         private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
         public void read() {
            lock.readLock().lock();
             System.out.println("读加锁");

             try {
    //            System.out.println(Thread.currentThread().getName());
                 Thread.sleep(3000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             lock.readLock().unlock();
             System.out.println("读解锁");

         }
         public void write() {
             lock.writeLock().lock();
             System.out.println("写加锁");

             try {
    //            System.out.println(Thread.currentThread().getName());
                 Thread.sleep(3000);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
             lock.writeLock().unlock();
             System.out.println("写解锁");

         }
    }

    读写锁的三个特质:

    1.公平和不公平

       【公平锁】获取锁的顺序:线程调用的顺序。

       【不公平锁:默认】获取锁的顺序和调用锁的顺序没有关系;相对来说,非公平锁的效率较高。

    2.读锁和写锁,都支持线程重进入。【一个线程可以同时拥有读锁和写锁

    3.锁降级:获取写锁 –> 获取读锁 –>释放写锁

    【获取锁的顺序:先获取写锁,在获取读锁】——重进入

    【读写锁顺序不支持顺序颠倒】

    import java.util.concurrent.locks.ReentrantReadWriteLock;

    public class MyReadWriteLock3 {
         public static void main(String[] args) throws Exception{
             ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
             readWriteLock.writeLock().lock();
             System.out.println("写 占锁");
             readWriteLock.readLock().lock();
             System.out.println("读 占锁");

            readWriteLock.writeLock().unlock();
             System.out.println("释放写锁");
             //此时效果相当于将写锁降级为读锁


         }
    }

    信号量

    public class MySemaphore {
         public static void main(String[] args) throws Exception{
             Semaphore semaphore = new Semaphore(10);
             semaphore.acquire(5);//添加信号量
             System.out.println(semaphore.availablePermits());
             semaphore.acquire(3);
             System.out.println(semaphore.availablePermits());
             semaphore.acquire(1);
             System.out.println(semaphore.availablePermits());
             semaphore.release(5);//释放信号量
             System.out.println(semaphore.availablePermits());
             semaphore.acquire(4);
             System.out.println(semaphore.availablePermits());
         }
    }

    阻塞队列:当队列中的数据满的时候,进入阻塞状态

    组赛队列分为:阻塞和非阻塞两种状态。

    public static void main(String[] args) throws Exception{
         BlockingQueue<String> bqueue = new ArrayBlockingQueue<String>(10);
         bqueue.add("hello");
         bqueue.offer("world");
         //put()添加元素,如果没有多余空间,方法会一直阻塞,直到队列中没有多余的空间   
    }

    阻塞栈【类似于 LinkedList】

    //本质:将集合进一步封装!        // 集合中 内部类 Deque queue 等

    public static void main(String[] args) throws Exception{
         BlockingDeque<String> bqueue = new LinkedBlockingDeque<String>(10);
         bqueue.addFirst("1");
         bqueue.putFirst("3");//有阻塞状态
    }



    条件变量

            Lock lock = new ReentrantLock();
             Condition condition = lock.newCondition();
             condition.await();
    //        condition.notifyAll();
             condition.signalAll();


    原子量:针对Java中所有的变量类型设计的一种原子化操作的变量。

    【原子量只能保证该原子量安全】

    //应用

    AtomicInteger ai = new AtomicInteger();
             AtomicBoolean ab;
             AtomicIntegerArray aisArray = new AtomicIntegerArray(3);
             aisArray.getAndSet(0, 11);
             aisArray.getAndSet(1, 12);
             aisArray.getAndSet(2, 11);
             AtomicReference<Double> aReference;
             AtomicReferenceArray<Short> asArray;

    //原子量自身是安全的,但是如果操作涉及其他变量,不能保证其他变量的线程安全。


    障碍器:必须等到所有子线程执行完毕以后,才会执行主线程,实际上,是子线程通知后进入等待状态,主线程执行完毕后,子线程停止等待。

    //将阻塞器与需要阻塞线程关联

    CyclicBarrier cyclicBarrier2 = new CyclicBarrier(5, new MainThread());
             new Thread(new SubThread(cyclicBarrier2)).start();
             new Thread(new SubThread(cyclicBarrier2)).start();
             new Thread(new SubThread(cyclicBarrier2)).start();
             new Thread(new SubThread(cyclicBarrier2)).start();
             new Thread(new SubThread(cyclicBarrier2)).start();

    class MainThread implements Runnable{

        @Override
         public void run() {
             // TODO Auto-generated method stub
             System.out.println("主线程启动");
         }
    }

    class SubThread implements Runnable{
         private final CyclicBarrier cyclicBarrier;
         public SubThread(final CyclicBarrier cyclicBarrier) {
             // TODO Auto-generated constructor stub
             this.cyclicBarrier =  cyclicBarrier;
         }
         @Override
         public void run() {
             // TODO Auto-generated method stub
             System.out.println("子线程启动");
             try {
                 cyclicBarrier.await();//通知次数达到 阻塞器定义的次数,启动对应的线程
                 System.out.println("通知结束"); //主线程执行完毕后,唤醒所有等待的子线程

             } catch (InterruptedException | BrokenBarrierException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
        
    }

    有返回值的线程:

    一个有返回值的线程

    但是:必须等到他执行完之后,才能拿到结果。

    //

    ExecutorService pool = Executors.newFixedThreadPool(3);
            
             Future<String> future = pool.submit(new Callable<String>() {

                @Override
                 public String call() throws Exception {
                     // TODO Auto-generated method stub
    //                return null;
                     return "这是callable返回字符串";
                 }
             });
            
             String result = future.get();
             System.out.println(result);      
             pool.execute(new Thread());
             pool.execute(new MyThread7());      
             pool.shutdown();

    运算阻塞:执行过程中线程不可中断,否则得不到结果。【考虑串行】

    最大线程并发数:CPU内核数。

    如果能够预见某次运算的执行期间过长,才可以判断其是运算阻塞。

    IO流阻塞:执行短暂,比如:读取某个数据,读取文件。【考虑并行】


    分布式:重【架构思想】——完整项目,若干模块!【系统架构】

    微服务【设计思路】为了解决这个问题。【业务设计】



    分段计算:Hadoop【不建议造成运算阻塞】【算MR / 存HDFS】

    1:计算大批量数据【MR-HIVE—JDBC】

    简单数据模型:流式计算

    Map: 拆分成若干块,可以把拆分的数据分发到不同主机上运算。拆分后的数据运算量合理范围!

    Shuffer:各个主机运算完后,把数据会陆续汇总到该阶段,用来负责分组。

    Reduce:汇总累计。

    可以通过合理的设计,避免运算阻塞,可以使其转化为IO流阻塞。



    Spring 单例

    Java EE:

    JDBC——数据库

    Servelet——页面交互【JSP】

    RestRestful ——Jason【本质】




    一个线程包含以下内容:

    1.一个指向当前被执行指令的指令指针

    2.一个栈

    3.一个寄存器值的集合

    4.一个私有的数据区

  • 相关阅读:
    [转]了解ASP.NET MVC几种ActionResult的本质:EmptyResult & ContentResult
    [转]XPath 语法
    [转]XSL 语言
    [转]项目经理面试指南
    [转]《精通css》笔记1:css选择器与优先级
    [转]jQuery 简介
    [转]Android 70道面试题
    [书目20130316].NET应用架构设计:原则、模式与实践
    [转]XPath语法 在C#中使用XPath示例
    [转]Android面试3
  • 原文地址:https://www.cnblogs.com/macro-renzhansheng/p/12567078.html
Copyright © 2011-2022 走看看