Java multithreading study notes (4) thread safety issues

What is thread safety:

    In a multithreaded environment, thread safety is unavoidable. In Java, you can use the synchronize keyword to solve thread safety issues.
Examples of thread insecurity:

public class Example09 {
    
    
    public static void main(String[] args) {
    
    
        BusTicket3 busTicket = new BusTicket3();
        //开启四个线程
        new Thread(busTicket, "窗口1").start();
        new Thread(busTicket, "窗口2").start();
        new Thread(busTicket, "窗口3").start();
        new Thread(busTicket, "窗口4").start();
    }
}
class BusTicket3 implements Runnable {
    
    
    private int ticket = 10;//车票数量
    public void run() {
    
    
        while (ticket > 0) {
    
    
            //获取线程的名字
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "正在发第" + ticket-- + "张票");
        }
    }
}

Operation result:
Insert picture description here
    As can be seen from the above operation result, four ticket windows sell ten tickets at the same time. Normally, the same ticket will not be sold twice. It is the thread insecurity that causes the same ticket to be sold repeatedly. Thread safety does not happen every time, and it does not mean that there is no security problem. We use the synchronize keyword to solve this problem.

Two uses of synchronize:

1. Synchronize code blocks

public class Example09 {
    
    
    public static void main(String[] args) {
    
    
        BusTicket3 busTicket = new BusTicket3();
        //开启四个线程
        new Thread(busTicket, "窗口1").start();
        new Thread(busTicket, "窗口2").start();
        new Thread(busTicket, "窗口3").start();
        new Thread(busTicket, "窗口4").start();
    }
}
class BusTicket3 implements Runnable {
    
    
    private int ticket = 10;//车票数量
    Object lock = new Object();//定义一个对象,作为同步代码块的锁
    public void run() {
    
    
        while (ticket > 0) {
    
    
            synchronized (lock) {
    
    //定义同步代码块
                try {
    
    
                    Thread.sleep(500);
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
                if (ticket > 0) {
    
    
                    //获取线程的名字
                    String threadName = Thread.currentThread().getName();
                    System.out.println(threadName + "正在发第" + ticket-- + "张票");
                } else {
    
    
                    break;
                }
            }
        }
    }
}

You can run the results yourself to see the effect

2. Synchronization method

public class Example09 {
    
    
    public static void main(String[] args) {
    
    
        BusTicket3 busTicket = new BusTicket3();
        //开启四个线程
        new Thread(busTicket, "窗口1").start();
        new Thread(busTicket, "窗口2").start();
        new Thread(busTicket, "窗口3").start();
        new Thread(busTicket, "窗口4").start();
    }
}
class BusTicket3 implements Runnable {
    
    
    private int ticket = 10;//车票数量
    public void run() {
    
    
       while (ticket > 0) {
    
    
           try {
    
    
               sellTicket();
               if (ticket <= 0) break;
           }catch (Exception e){
    
    
               e.printStackTrace();
           }
        }
    }
    //使用synchronized修饰卖票的方法
    private synchronized void sellTicket() throws Exception{
    
    
        if (ticket > 0){
    
    
            Thread.sleep(500);
            //获取线程的名字
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "正在发第" + ticket-- + "张票");
        }
    }
}

Usage of lock:

    Lock was introduced in Java 1.6. The introduction of Lock makes the lock operability. What does it mean? That is, when we need to manually acquire and release the lock, we can even interrupt the acquisition and the synchronization feature of timeout acquisition, but from the perspective of use, Lock is obviously not synchronized, which is convenient and quick to use.

Lock API

Insert picture description here

Use of the lock method

Examples:

public class Example10 {
    
    
    public static void main(String[] args) {
    
    
        BusTicket4 busTicket = new BusTicket4();
        //开启两个线程
        new Thread(busTicket, "窗口1").start();
        new Thread(busTicket, "窗口2").start();
    }
}
//BusTicket4实现Runnable接口
class BusTicket4 implements Runnable {
    
    
    private Lock lock = new ReentrantLock(); // ReentrantLock是Lock的子类
    private int ticket = 10;//车票数量
    public void run() {
    
    
        lock.lock();//加锁
        for (int i = 1; i <= 5; i++) {
    
    
            System.out.println(Thread.currentThread().getName() + "在出售第" + i + "张");
            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        lock.unlock();//释放锁
    }
}

operation result:
Insert picture description here

Use of tryLock​() method

tryLock​(), the lock can be acquired only when the lock is idle (the lock will not wait if the lock is not acquired, and the lock() will enter the blocking state if the lock is not acquired), the return value is boolean type, the acquisition of the lock is true, otherwise it is false.
Examples:

public class Example11 {
    
    
    public static void main(String[] args) {
    
    
        BusTicket5 busTicket = new BusTicket5();
        //开启两个线程
        new Thread(busTicket, "窗口1").start();
        new Thread(busTicket, "窗口2").start();
    }
}

//BusTicket4实现Runnable接口
class BusTicket5 implements Runnable {
    
    
    private Lock lock = new ReentrantLock(); // ReentrantLock是Lock的子类
    private int ticket = 10;//车票数量
    public void run() {
    
    
        if (lock.tryLock()) {
    
    //lock.tryLock()返回值是一个Boolean值
            System.out.println(Thread.currentThread().getName() + ":获得锁");
            for (int i = 1; i <= ticket; i++) {
    
    
                System.out.println(Thread.currentThread().getName() + "在出售第" + i + "张");
                try {
    
    
                    Thread.sleep(100);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
            lock.unlock();
        }else {
    
    
            System.out.println(Thread.currentThread().getName() + ":未获得锁");
        }
    }
}

operation result:
Insert picture description here

Use of tryLock​(long time, TimeUnit unit) method

    If the lock is available, this method immediately returns the value true. If the lock is not available, the current thread will be disabled for thread scheduling and will be dormant before one of the following three conditions occurs:

  • The current thread acquires the lock.
  • Some other threads interrupt the current thread.
  • When the waiting time has passed, return false
    instance:
public class Example12 {
    
    
    public static void main(String[] args) {
    
    
        BusTicket6 busTicket = new BusTicket6();
        //开启两个线程
        new Thread(busTicket, "窗口1").start();
        new Thread(busTicket, "窗口2").start();
        new Thread(busTicket, "窗口3").start();
    }
}

//BusTicket4实现Runnable接口
class BusTicket6 implements Runnable {
    
    
    private Lock lock = new ReentrantLock(); // ReentrantLock是Lock的子类
    private int ticket = 10;//车票数量

    public void run() {
    
    
        try {
    
    
            if (lock.tryLock(1000, TimeUnit.MICROSECONDS)) {
    
    
                System.out.println(Thread.currentThread().getName() + ":获得锁");
                for (int i = 1; i <= ticket; i++) {
    
    
                    System.out.println(Thread.currentThread().getName() + "在出售第" + i + "张");
                    try {
    
    
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
                lock.unlock();
            } else {
    
    
                System.out.println(Thread.currentThread().getName() + ":未获得锁");
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
}

Come on! ! !

Guess you like

Origin blog.csdn.net/qq_42494654/article/details/109521304