java achieve thread-safe three ways

A program will be converted to process up and running in time, usually contain multiple threads.

  Typically, a process time-consuming operations (such as long loop, file uploading and downloading, network resource access, etc.), often using multiple threads to solve.

For example, the display life, bank money problem, the problem multiple train ticket window, usually involves the issue of concurrency, which requires multi-threading technology.

  When the process has multiple concurrent threads entering a code block important data, modify data in the process, likely to lead to thread safety issues, resulting in abnormal data. For example, normal logic, the same number of tickets sold only once, but because of security thread is sold several times, which led to the actual business exceptions.

 

Now we have to demonstrate to the ticket issue thread-safety issues

1, in the case of multi-threaded data protection does not lead to a situation of

复制代码
public class ThreadUnSecurity {
    
    static int tickets = 10;
    
    class SellTickets implements Runnable{

        @Override
        public void run() {
            // 未加同步时产生脏数据
            while(tickets > 0) {
                
                System.out.println(Thread.currentThread().getName()+"--->售出第:  "+tickets+" 票");
                tickets--;
                
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
            }
            
            if (tickets <= 0) {
                
                System.out.println(Thread.currentThread().getName()+"--->售票结束!");
            }
        }
    }
    
    
    public static void main(String[] args) {
        
        
        SellTickets sell = new ThreadUnSecurity().new SellTickets();
        
        Thread thread1 = new Thread(sell, "1号窗口");
        Thread thread2 = new Thread(sell, "2号窗口");
        Thread thread3 = new Thread(sell, "3号窗口");
        Thread thread4 = new Thread(sell, "4号窗口");
        
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        
        
    }
    

}
复制代码

The code run results:

复制代码
1号窗口--->售出第:  10 票
3号窗口--->售出第:  10 票
2号窗口--->售出第:  10 票
4号窗口--->售出第:  10 票
2号窗口--->售出第:  6 票
1号窗口--->售出第:  5 票
3号窗口--->售出第:  4 票
4号窗口--->售出第:  3 票
2号窗口--->售出第:  2 票
4号窗口--->售出第:  1 票
1号窗口--->售出第:  1 票
3号窗口--->售票结束!
2号窗口--->售票结束!
1号窗口--->售票结束!
4号窗口--->售票结束!
复制代码

我们可以看出同一张票在不对票数进行保护时会出现同一张票会被出售多次!由于线程调度中的不确定性,读者在演示上述代码时,出现的运行结果会有不同。

 

第一种实现线程安全的方式

  同步代码块

复制代码
package com.bpan.spring.beans.thread;

import com.sun.org.apache.regexp.internal.recompile;

public class ThreadSynchronizedSecurity {
    
    static int tickets = 10;
    
    class SellTickets implements Runnable{

        @Override
        public void run() {
            // 同步代码块
            while(tickets > 0) {
                
                synchronized (this) {
                    
//                    System.out.println(this.getClass().getName().toString());
                    
                    if (tickets <= 0) {
                        
                        return;
                    }
                    
                    System.out.println(Thread.currentThread().getName()+"--->售出第:  "+tickets+" 票");
                    tickets--;
                    
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                
                if (tickets <= 0) {
                    
                    System.out.println(Thread.currentThread().getName()+"--->售票结束!");
                }
            }
        }
    }
    
    
    public static void main(String[] args) {
        
        
        SellTickets sell = new ThreadSynchronizedSecurity().new SellTickets();
        
        Thread thread1 = new Thread(sell, "1号窗口");
        Thread thread2 = new Thread(sell, "2号窗口");
        Thread thread3 = new Thread(sell, "3号窗口");
        Thread thread4 = new Thread(sell, "4号窗口");
        
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        
        
    }
    

}
复制代码

Readers are free to debug output, the situation is the same tickets sold many times does not occur.

 

The second way

  Synchronization method

复制代码
package com.bpan.spring.beans.thread;

public class ThreadSynchroniazedMethodSecurity {
    
    
    static int tickets = 10;
    
    class SellTickets implements Runnable{

        @Override
        public void run() {
            //同步方法
            while (tickets > 0) {
                
                synMethod();
                
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
                if (tickets<=0) {
                    
                    System.out.println(Thread.currentThread().getName()+"--->售票结束");
                }
                
            }
            
            
        }
        
        synchronized void synMethod() {
            
            synchronized (this) {
                if (tickets <=0) {
                    
                    return;
                }
                
                System.out.println(Thread.currentThread().getName()+"---->售出第 "+tickets+" 票 ");
                tickets-- ;
            }
            
        }
        
    }
    public static void main(String[] args) {
        
        
        SellTickets sell = new ThreadSynchroniazedMethodSecurity().new SellTickets();
        
        Thread thread1 = new Thread(sell, "1号窗口");
        Thread thread2 = new Thread(sell, "2号窗口");
        Thread thread3 = new Thread(sell, "3号窗口");
        Thread thread4 = new Thread(sell, "4号窗口");
        
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        
    }

}
复制代码

Readers can debug the code above their own operating results

 

The third way

  Lock locking mechanism, Lock objects created by using lock () lock, unlock () Unlock to protect specific code block

复制代码
package com.bpan.spring.beans.thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadLockSecurity {
    
    static int tickets = 10;
    
    class SellTickets implements Runnable{
        
        Lock lock = new ReentrantLock();

        @Override
        public void run() {
            // Lock锁机制
            while(tickets > 0) {
                
                try {
                    lock.lock();
                    
                    if (tickets <= 0) {
                        
                        return;
                    }
                        
                    System.out.println(Thread.currentThread().getName()+"--->售出第:  "+tickets+" 票");
                    tickets--;
                } catch (Exception e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }finally {
                    
                    lock.unlock();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
                
            if (tickets <= 0) {
                
                System.out.println(Thread.currentThread().getName()+"--->售票结束!");
            }
            
        }
    }
    
    
    public static void main(String[] args) {
        
        
        SellTickets sell = new ThreadLockSecurity().new SellTickets();
        
        Thread thread1 = new Thread(sell, "1号窗口");
        Thread thread2 = new Thread(sell, "2号窗口");
        Thread thread3 = new Thread(sell, "3号窗口");
        Thread thread4 = new Thread(sell, "4号窗口");
        
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        
        
    }
    

}
复制代码

 

 最后总结:

  由于synchronized是在JVM层面实现的,因此系统可以监控锁的释放与否;而ReentrantLock是使用代码实现的,系统无法自动释放锁,需要在代码中的finally子句中显式释放锁lock.unlock()。

  另外,在并发量比较小的情况下,使用synchronized是个不错的选择;但是在并发量比较高的情况下,其性能下降会很严重,此时ReentrantLock是个不错的方案。

 

 补充:  

  When using synchronized code blocks may be used with wait (), notify (), nitifyAll (), thus further communication thread.
Which, wait () method will release the possession of the object lock, the current thread into the wait pool, the release cpu, while other threads are waiting to seize the lock, get the thread to run the program locks; threads sleep () method is said the current thread to sleep for some time, during sleep, temporarily release the cpu, but does not release the object lock, that is, during sleep, other threads are still unable to enter the internal code synchronized protected end of the current thread to sleep, cpu will regain the right to perform, to perform the synchronization protection code.
wait () and sleep () is the biggest difference wait () releases the object lock, and sleep () does not release the object lock.

  notify () method wakes up a thread calling wait because the object () is in a wait state, so that the thread has the opportunity to acquire the object lock. After calling notify (), the current thread will not release the lock immediately, but continue executing the current code, until the synchronized code executed completely, will release the object lock. JVM dispatches a thread in the thread waiting for the lock to get the object, execute code.

  Note that, wait () and notify () must be called synchronized code block.

  notifyAll () is a wake up all waiting threads.

 

The following is example code,

复制代码
package com.bpan.spring.beans.thread;

public class ThreadDemo {
    
    static final Object obj = new Object();
    
    //第一个子线程
    static class ThreadA implements Runnable{

        @Override
        public void run() {
            
            
            int count = 10;
            while(count > 0) {
                
                synchronized (ThreadDemo.obj) {
                    
                    System.out.println("A-----"+count);
                    count--;
                    
                    synchronized (ThreadDemo.obj) {
                        
                        //notify()方法会唤醒因为调用对象的wait()而处于等待状态的线程,从而使得该线程有机会获取对象锁。
                        //调用notify()后,当前线程并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,
                        ThreadDemo.obj.notify();
                        
                        try {
                            ThreadDemo.obj.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
            
        }
        
    }
    
    static class ThreadB implements Runnable{
        
        
        @Override
        public void run() {
            
            int count = 10;
            
            while(count > 0) {
                
                synchronized (ThreadDemo.obj) {
                    System.out.println("B-----"+count);
                    count--;
                    
                    synchronized (ThreadDemo.obj) {
                    
                        //notify()方法会唤醒因为调用对象的wait()而处于等待状态的线程,从而使得该线程有机会获取对象锁。
                        //调用notify()后,当前线程并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,
                        ThreadDemo.obj.notify();
                        
                        try {
                            ThreadDemo.obj.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    
                }
                
            }
            
        }
        
    }
    
    public static void main(String[] args) {
        
        
        new Thread(new ThreadA()).start();
        new Thread(new ThreadB()).start();
        
    }

}
复制代码

 https://www.cnblogs.com/revel171226/p/9411131.html

Guess you like

Origin www.cnblogs.com/ldddd/p/11422033.html