zoukankan      html  css  js  c++  java
  • JAVA高并发处理------多线程

    线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

    分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),一个线程想要执行synchronized修饰的方法里的代码:1 尝试获得锁  2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)

    synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"。取得的锁都是对象锁,而不是把一段代码(方法)当做锁,所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)。

    锁对象的改变问题:例如下面代码中,当lock发生变化后,t1开始后,t2直接开始。如果去掉将lock改变的代码,则是t1结束后t2才会开始。但是同一对象属性的修改不会影响锁的情况,比如下面代码的lock现在是一个带属性的对象,如果改变该对象的属性,结果还是t1结束后t2才会开始。

    package com.bjsxt.base.sync006;
    /**
     * 锁对象的改变问题
     * @author alienware
     *
     */
    public class ChangeLock {
    
        private String lock = "lock";
        
        private void method(){
            synchronized (lock) {
                try {
                    System.out.println("当前线程 : "  + Thread.currentThread().getName() + "开始");
                    lock = "change lock";
                    Thread.sleep(2000);
                    System.out.println("当前线程 : "  + Thread.currentThread().getName() + "结束");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        
        public static void main(String[] args) {
        
            final ChangeLock changeLock = new ChangeLock();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    changeLock.method();
                }
            },"t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    changeLock.method();
                }
            },"t2");
            t1.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
        
    }

     死锁问题:在设计程序时就应该避免双方相互持有对方的锁的情况,如下代码,会发生死锁问题,t1 进入lock1执行, t2 进入lock2执行。之后,t1去等待lock2对象解锁,t2去等待lock1对象解锁,这时谁也不能解锁,程序就会停在这里一直等待,这就是死锁问题。

    package com.bjsxt.base.sync006;
    
    /**
     * 死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况
     * @author alienware
     *
     */
    public class DeadLock implements Runnable{
    
        private String tag;
        private static Object lock1 = new Object();
        private static Object lock2 = new Object();
        
        public void setTag(String tag){
            this.tag = tag;
        }
        
        @Override
        public void run() {
            if(tag.equals("a")){
                synchronized (lock1) {
                    try {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock1执行");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock2) {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock2执行");
                    }
                }
            }
            if(tag.equals("b")){
                synchronized (lock2) {
                    try {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock2执行");
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock1) {
                        System.out.println("当前线程 : "  + Thread.currentThread().getName() + " 进入lock1执行");
                    }
                }
            }
        }
        
        public static void main(String[] args) {
            
            DeadLock d1 = new DeadLock();
            d1.setTag("a");
            DeadLock d2 = new DeadLock();
            d2.setTag("b");
             
            Thread t1 = new Thread(d1, "t1");
            Thread t2 = new Thread(d2, "t2");
             
            t1.start();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
        
    
        
    }

    volatile:用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的值。volatile很容易被误用,用来进行原子性操作。volatile关键字不具备synchronized关键字的原子性(同步)

    AtomicInteger:一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。注意:atomic类只保证本身方法的原子性,并不保证多次操作的原子性。比如说,我们使用AtomicInteger进行一次加十操作是具有原子性的,而同样是加十的操作,分成先加1,再加2,再加3,再加4这样四次操作,就不能保证原子性了。

    脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

    在线程里调用变量变量必须用final修饰

    wait释放锁,notify不释放锁。配合synchronized会有不实时的问题,这时有了下面的类。

    CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

    主要方法

     public CountDownLatch(int count); 初始化计时器数量

     public void countDown();

     public void await() throws InterruptedException

    构造方法参数指定了计数的次数

    countDown方法,当前线程调用此方法,则计数减一

    await方法,调用此方法会一直阻塞当前线程,直到计时器的值为0

    ThreadLocal:ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

    多线程中的单例模式:

    1.静态内部类--static inner class(饥汉模式)

    package com.bjsxt.base.conn011;
    
    public class Singletion {
        
        private static class InnerSingletion {
            private static Singletion single = new Singletion();
        }
        
        public static Singletion getInstance(){
            return InnerSingletion.single;
        }
        
    }

    2.双重确认--dubble check instance(懒汉模式)

    package com.bjsxt.base.conn011;
    
    public class DubbleSingleton {
    
        private static DubbleSingleton ds;
        
        public  static DubbleSingleton getDs(){
            if(ds == null){
                try {
                    //模拟初始化对象的准备时间...
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (DubbleSingleton.class) {
                    if(ds == null){
                        ds = new DubbleSingleton();
                    }
                }
            }
            return ds;
        }
        
        public static void main(String[] args) {
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(DubbleSingleton.getDs().hashCode());
                }
            },"t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(DubbleSingleton.getDs().hashCode());
                }
            },"t2");
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(DubbleSingleton.getDs().hashCode());
                }
            },"t3");
            
            t1.start();
            t2.start();
            t3.start();
        }
        
    }

    同步类容器(不建议使用)

    并发类容器

     

     

    并发Queue:

     

    Futuer模式

    Master-Worker模式

  • 相关阅读:
    BZOJ3670:[NOI2014]动物园(KMP)
    415. [HAOI2009] 旅行
    U10223 Cx大帝远征埃及
    U10206 Cx的治疗
    2741. [济南集训 2017] 掰巧克力
    复习题目汇总 over
    7-20 表达式转换(25 分)
    7-19 求链式线性表的倒数第K项(20 分)(单链表定义与尾插法)
    7-18 银行业务队列简单模拟(25 分)
    7-17 汉诺塔的非递归实现(25 分)(有待改进)
  • 原文地址:https://www.cnblogs.com/lm970585581/p/7459937.html
Copyright © 2011-2022 走看看