zoukankan      html  css  js  c++  java
  • 线程同步

    线程同步

    • 当多个线程操作同一资源,例如上万人同时抢几张火车票,几个人都想上厕所但只有一个坑位。这个时候就会由于资源的抢夺,导致程序输出错误的结果,比如说,一个人还没上完厕所,另一个就进去了。
    • 线程同步就是用来解决上述问题,总的来说就是通过队列+锁的方式来控制对公共资源操作时不受其他线程影响
    • 通过加锁的方式保证了程序有条不紊的运行,但是一个线程持有锁会导致其他所有线程被挂起,加锁解锁导致了比较多的上下文切换和调度延时,因此牺牲了一定的效率
    • 在Java中是通过锁机制synchronized来实现的,主要可以分为两种
    1. 同步方法 public synchronized void method(int args){}

    2. 同步块 synchronized(Obj){}

    代码演示

    例1-同步方法

    package MultiProcess;
    
    public class Unsafe {
        public static void main(String[] args) {
            BuyTicket buyTicket = new BuyTicket();
            new Thread(buyTicket, "我").start();
            new Thread(buyTicket, "我室友").start();
            new Thread(buyTicket, "黄牛").start();
        }
    }
    
    class BuyTicket implements Runnable{
        boolean flag = true;
        private int ticketNums = 10;
    
        @Override
        public void run() {
            while(flag){
                try {
                    buy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private void buy() throws InterruptedException{
            if(ticketNums <= 0){
                flag = false;
                return;
            }
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + "买了第" + ticketNums-- + "张票");
        }
    }
    
    结果
    我买了第4张票
    我室友买了第3张票
    黄牛买了第2张票
    我买了第1张票
    黄牛买了第-1张票
    我室友买了第0张票
    

    由于多线程操作同一资源ticketNum,进行ticketNum--,导致了线程不安全问题。因为ticketNum--操作需要经过三个步骤,把ticketNum的值读到寄存器中,进行-1运算,写回内存。所以A线程刚把ticketNum放到寄存器,B线程就会读到寄存器里的值,没有读-1运算后的值,导致了结果的异常。

    添加同步方法
    package MultiProcess;
    
    public class Unsafe {
        public static void main(String[] args) {
            BuyTicket buyTicket = new BuyTicket();
            new Thread(buyTicket, "我").start();
            new Thread(buyTicket, "我室友").start();
            new Thread(buyTicket, "黄牛").start();
        }
    }
    
    class BuyTicket implements Runnable{
        boolean flag = true;
        private int ticketNums = 10;
    
        @Override
        public void run() {
            while(flag){
                try {
                    buy();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private synchronized void buy() throws InterruptedException{
            if(ticketNums <= 0){
                flag = false;
                return;
            }
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + "买了第" + ticketNums-- + "张票");
        }
    }
    
    结果
    黄牛买了第7张票
    我买了第6张票
    黄牛买了第5张票
    黄牛买了第4张票
    我室友买了第3张票
    黄牛买了第2张票
    黄牛买了第1张票
    
    

    例2-同步块

    package MultiProcess;
    import java.util.ArrayList;
    import java.util.List;
    public class UnsafeList {
        public static void main (String[] args) {
            List<String> list = new ArrayList<String>();
            for(int i = 0; i < 100000; i++){
                new Thread(()->{
                    list.add(Thread.currentThread().getName());
                }).start();
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(list.size());
        }
    }
    
    
    结果
    99983
    

    因为多个线程可能将元素放到了同一位置上

    添加同步块
    package MultiProcess;
    import java.util.ArrayList;
    import java.util.List;
    public class UnsafeList {
        public static void main (String[] args) {
            List<String> list = new ArrayList<String>();
            for(int i = 0; i < 100000; i++){
                new Thread(() -> {
                    synchronized (list) {
                        list.add(Thread.currentThread().getName());
                    }
                }).start();
            }
    
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(list.size());
        }
    }
    
    结果
    100000
    
  • 相关阅读:
    温故而知新 js 点击空白处关闭气泡
    javascript 打印错误信息 catch err
    ajax application/json 的坑
    nodejs 的好基友:pm2
    有道翻译 / 百度翻译Api
    PHP 正则表达式
    php 正则替换
    github get 请求指定页面的代码
    H5 input 聚焦 置顶
    autoHotKey 一些脚本积累
  • 原文地址:https://www.cnblogs.com/happysml/p/13836764.html
Copyright © 2011-2022 走看看