High concurrent programming series (b)

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https: //blog.csdn.net/weixin_43874301/article/details/102383087

High concurrent programming series (b)

High concurrency programming series

Program in the implementation process, if an exception occurs, the default condition of the lock is released
so that concurrent processing, there is an exception to be more careful, otherwise inconsistencies occur,
for example, in a web app process, multiple servlet common threads access the same resource, then if exception handling is not suitable,
an exception is thrown in the first thread, other thread synchronization code to enter the area, it is possible to access data anomalies generated.
So be very careful synchronization processing business logic exception
to this case t1 t2 lock is released before the start
if you do not want to release a lock you join try {} catch {}

public class Tj {

    int count = 0;
    synchronized void m() {
        System.out.println(Thread.currentThread().getName() + "start");
        while (true) {
            count ++;
            System.out.println(Thread.currentThread().getName() + "count: " + count);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (count == 5) {
                //此处抛出异常,锁将被释放,要想不释放就在此处进行catch,然后循环继续.
                int i = 1/0;
            }

        }
    }

    public static void main(String[] args) {

        Tj t = new Tj();
        Runnable r = new Runnable() {
            @Override
            public void run() {
                t.m();
            }
        };

        new Thread(r,"t1").start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(r,"t2").start();

    }

}

operation result

volatile keyword, so that a variable is visible among multiple threads
AB threads are used in a variable, java default is A thread to keep a copy, so if the threads modifies the variable B, then A thread may not know
the use of volatile edit keywords, make all the threads will read variable values.
in the following code, running is present in the heap memory t object,
when t1 threads started running, running value will t1 read from memory workspace thread, during operation, the direct use of copy,
not always to use colatile, it will force all threads to read the heap running value
when olatile not guarantee multiple threads running together modify variables the issue has been brought, also said that volatile is not a substitute synchronized

public class Tk {

    //对比一下有无volatitle ,整个程序运行结果的区别
    /*volatile*/ boolean running = true;
    void m(){
        System.out.println("m statr");
        while (running) {

        }
        System.out.println("m end");
    }

    public static void main(String[] args) {
        Tk t = new Tk();

        new Thread(t::m,"t1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t.running = false;

    }

}

There volatile

When volatile does not guarantee multiple threads running together modify variables caused by inconsistencies, that is not a substitute for synchronized volatile
run the following program, the results of the analysis
to create a 10 threads
difference between volatile and synchronized the
volatile guarantee does not guarantee the visibility of the atom sex; synchronized both to ensure visibility and ensure atomicity;
efficiency synchronized volatile than the low number of interviews will be out

public class Tl {

    volatile int count = 10;
    void m() {
        for (int i=0; i<10000;i++) count++;
    }

    public static void main(String[] args) {
        Tl t = new Tl();

        List<Thread> threads = new ArrayList<Thread>();

        for (int i=0; i<10; i++) {
            threads.add(new Thread(t::m, "thread" + i));
        }

        threads.forEach((o)->o.start());

        threads.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);

    }

}

运行情况
运行情况

A more efficient way to solve the same problem using AtomXXX classes. Class atoms
AtmXXX methods are atomic class itself, but the method can not guarantee that a plurality of calls are atomic.

public class Tm {

    /*volatile int count = 0;*/

    AtomicInteger count = new AtomicInteger(0);

    synchronized void m(){
        for (int i=0; i<10000; i++)
            //if(count.get()<1000)      注意这里     如果未加锁,之间还会有其他线程插进来
            count.incrementAndGet(); //count++
    }

    public static void main(String[] args) {

        Tm  t = new Tm();

        List<Thread> threads = new ArrayList<Thread>();

        for (int i=0; i<10; i++) {
            threads.add(new Thread(t::m,"thread" + i));
        }

        threads.forEach((o)->o.start());

        threads.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);

    }

}

运行结果

volatile 关键字,使一个变量在多个线程之间可见
A B 线程都用到一个变量,java默认是A线程中保留一份copy,这样如果B线程修改了该变量,则A线程未必知道.
使用volatile 关键字,会让所有线程都会读到变量值的修改.
在下面代码中,running是存在于堆内存的t对象中,
当线程t1开始运行的时候,会把running的值从内存中读到t1线程的工作区,在运行过程中,直接使用copy,
并不是每次都去使用colatile,将会强制所有线程去堆内存中读取running的值
volatile 并不能保证多个线程共同修改running变量时所带来的一直问题,也就说volatile不能代替synchronized

public class Tk {

    //对比一下有无volatitle ,整个程序运行结果的区别
    /*volatile*/ boolean running = true;
    void m(){
        System.out.println("m statr");
        while (running) {

        }
        System.out.println("m end");
    }

    public static void main(String[] args) {
        Tk t = new Tk();

        new Thread(t::m,"t1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t.running = false;

    }

}

不加volatile
不添加volatile
添加volatile
添加volatile

volatile 并不能保证多个线程共同修改running 变量 时所带来的不一致问题,也就是说volatile 不能代替synchronized
运行下面的程序,分析结果
创建10个线程
volatile 和 synchronized 的区别
volatile 保证可见性并不保证原子性;synchronized 既保证可见性又保证原子性;
synchronized的效率要比volatile低不少 面试必出

public class Tl {

    volatile int count = 10;
    void m() {
        for (int i=0; i<10000;i++) count++;
    }

    public static void main(String[] args) {
        Tl t = new Tl();

        List<Thread> threads = new ArrayList<Thread>();

        for (int i=0; i<10; i++) {
            threads.add(new Thread(t::m, "thread" + i));
        }

        threads.forEach((o)->o.start());

        threads.forEach((o)->{
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);

    }

}

运行结果1
运行结果2

解决同样的问题的更高效的方法,使用AtomXXX类.原子类
AtmXXX类本身方法都是原子性的,但是不能保证多个方法调用是原子性的.

public class Tm {

    /*volatile int count = 0;*/

    AtomicInteger count = new AtomicInteger(0);

    synchronized void m(){
        for (int i=0; i<10000; i++)
            //if(count.get()<1000)             如果未加锁,之间还会有其他线程插进来
            count.incrementAndGet(); //count++
    }

    public static void main(String[] args) {

        Tm  t = new Tm();

        List<Thread> threads = new ArrayList<Thread>();

        for (int i=0; i<10; i++) {
            threads.add(new Thread(t::m,"thread" + i));
        }

        threads.forEach((o) -> o.start());

        threads.forEach((o) -> {
            try {
                o.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);

    }

}

运行结果

synchonized optimized
synchronization code statement in the block as possible.
Comparative m1 and m2

public class Tn {

    int count = 0;
    synchronized void m1() {

        //do sth need sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //业务逻辑中只有下面这句需要synchronized,这时不应该给整个方法上都上锁
        count++;

        //do sth need not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    void m2() {
        //do sth need not sync
        try{
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //业务逻辑中只有下面这句需要sync 时不应该给整个方法上锁
        //采用细粒度的锁,可以使线程争用时间变短,从而提高效率  细粒度锁要比粗粒度锁效率要高
        synchronized (this) {
            count++;
        }
        //do sth need not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //do sth not sync
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

Lock an object o, o if the property changes, does not affect use.
But if o into another object, the object lock changed.
Should avoid locking object reference into another target

public class To {

    Object o = new Object();

    void m() {
        synchronized (o) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
       To t = new To();
       //启动线程
        new Thread(t::m, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //创建第二个线程
        Thread t2 = new Thread(t::m, "t2");
        //锁定对象发生变化,所以t2线程得以进行,如注释掉这句话,线程2将永远得不到执行机会
        //锁是锁在堆内存  不是锁在栈内存
        t.o = new Object();

        t2.start();

    }

}

Do not lock the object as a string constant
in m1 m2 below the lock is actually the same object
more strange phenomenon will happen in this case, for example, you use a library, the library code is locked "Hello "
but you are not to the source code, so you locked in your own code," Hello ", which may occur when a deadlock blocking very strange,
because between your program and you use the library inadvertently used the same lock.

public class Tp {

    String s1 = "Hello";
    String s2 = "Hello";

    void m1() {
        synchronized (s1) {

        }
    }

    void m2() {
        synchronized (s2) {

        }
    }
    
}

Once the interview questions
to achieve a container, providing two programs add size
to write two threads, the thread ten elements added to the vessel, monitoring the number of elements realized thread 2, when the number to five, and prompt threads 2 end.
However, t2 thread infinite loop is a waste of cpu, if not infinite loop, how to do it?

public class Tq {

    //添加volatile 使t2能够得到通知

    volatile List lists = new ArrayList();

    public void add(Object o) {
        lists.add(o);
    }

    public int size() {
        return lists.size();
    }

    public static void main(String[] args) {
        Tq t = new Tq();

        new Thread(()-> {
           for (int i=0; i<10; i++) {
               t.add(new Object());
               System.out.println("add" + i);
           }

           try {
               TimeUnit.SECONDS.sleep(1);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
        },"t1").start();

        new Thread(()-> {
           while (true) {
               if (t.size() == 5) {
                   break;
               }
           }
            System.out.println("t2结束");
        },"t2").start();

    }

}

Use wait and notify to do here, will wait to release the lock, and notify will not release the lock
should be noted that this approach must first ensure the implementation of t2, t2 is to let listeners can.
Read the following procedures and analyze the output results.
can not read the output size = 5 t2 quit, but at the end of t1 t2 can only receive a notification introduced
think about why
wait is to call the object being locked wait notify method

public class Ts {

    volatile List lists = new ArrayList();

    public void add(Object o) {
        lists.add(o);
    }

    public int size() {
        return lists.size();
    }

    public static void main(String[] args) {
        Ts t = new Ts();

        final Object lock = new Object();

        new Thread(() -> {
           synchronized(lock) {
               System.out.println("t2启动");
               if (t.size() != 5) {
                   try {
                       lock.wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
               System.out.println("t2结束");
           }
        },"t2").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println("t1启动");
            synchronized(lock) {
                for (int i=0; i<10; i++) {
                    t.add(new Object());
                    System.out.println("add" + i);

                    if (t.size() == 5) {
                        lock.notify();
                    }

                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"t1").start();

    }

}

运行结果

This is when the size = 5 when, t1 threading, at the same time releases the lock wake T2, t2 executed, t2 execution ends wake-up calls notify t1.

public class Tt {

    volatile List lists = new ArrayList();

    public void add(Object o) {
        lists.add(o);
    }

    public int size() {
        return lists.size();
    }

    public static void main(String[] args) {
        Ts t = new Ts();

        final Object lock = new Object();

        new Thread(() -> {
            synchronized(lock) {
                System.out.println("t2启动");
                if (t.size() != 5) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("t2结束");
                //通知t1继续执行·
                lock.notify();
            }
        },"t2").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println("t1启动");
            synchronized(lock) {
                for (int i=0; i<10; i++) {
                    t.add(new Object());
                    System.out.println("add" + i);

                    if (t.size() == 5) {
                        lock.notify();
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"t1").start();

    }

}

运行结果

Guess you like

Origin www.cnblogs.com/mzdljgz/p/11641707.html