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

    线程同步锁

    sychronized关键字: 把有可能出现问题的代码包起来,一次只让一个线程执行。通过sychronized关键字实现同步。当多个对象操作共享数据时,可以使用同步锁解决线程安全问题。

    1. 格式:

    synchronized(对象){
        // 需要同步的
    }
    

    1.1 注意点:

    • 锁的位置: 不能太大, 会降低效率. 也不能太小, 相当于没锁住. 所以要找一个合适的位置
    • 锁的对象: 要求多个线程间使用的是同一把锁

    1.2 使用范围:

    可以修饰方法, 也可以用在代码块上

    2. 概念

    2.1 原理

    是指给你的共享资源加锁, 还是可以让多个线程操作共享资源, 只不过哪个线程有钥匙, 拿着钥匙进来开锁使用共享资源, 没有钥匙的线程等待.

    2.2 同步和异步的区别:

    • 同步: 是需要拿着钥匙开锁, 同一时刻只能有一个线程共享资源, 其他线程排队. 牺牲了效率, 提高了安全
    • 异步: 是没有排队的线程, 大家同时使用了共享资源. 对数据不安全, 效率高

    2.3 同步锁的特点:

    1. 前提1,同步需要两个或者两个以上的线程。
    2. 前提2,多个线程间必须使用同一个锁。
    3. 同步的缺点是会降低程序的执行效率, 为了保证线程安全,必须牺牲性能。
    4. 可以修饰方法称为同步方法,使用的锁对象是this。
    5. 可以修饰代码块称为同步代码块,锁对象可以任意。

    3. 使用案例

    注意点:

    • 可以把有想成安全隐患的的代码锁起来-- 同步的锁代码块
    • 锁的位置: 要合理, 不嫩太大也不能太小. 建议从共享资源开始位置一直到使用刚结束都锁起来
    • 锁的对象: 代码块的锁对象可以是任意的对象, 只要是多个线程间同一个对象就可以. 也可以是字符串

    3.1 同步代码块案例

    售票案例:

    // 这个类用来模拟多线程售票
    public class Test1_Tickets2 {
        public static void main(String[] args) {
            MyTickets target = new MyTickets();
            // 第一个参数是绑定的Runnable实现类对象, 第二个参数是线程的名称
            Thread t1 = new Thread(target, "窗口1");
            Thread t2 = new Thread(target, "窗口2");
            Thread t3 = new Thread(target, "窗口3");
            Thread t4 = new Thread(target, "窗口4");
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    
    // 创建类实现接口
    class MyTickets implements Runnable {
        // 定义变量, 记录票数
        int tickets = 100;
        // 写业务
        @Override
        public void run() {
            while (true) { // 一直卖票
                synchronized ("锁") { //括号中的对象必须是多个线程公共的一个对象
                    if (tickets > 0) { // 有票就卖
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // 打印线程名称和票数
                        System.out.println(Thread.currentThread().getName() + " : " + tickets --);
                    } else { // 没票就停
                        break;
                    }
                }
            }
        }
    }
    

    加了线程锁之后, 就不会出现超卖和重卖的情况了

    3.2 方法中使用

    当一个方法被synchronized修饰后,那么该方法称为同步方法,即:多个线程不能同时在方法内部执行,从而解决了并发的安全问题.

    在方法上使用synchronize,那么同步监听器对象是当前方法所属对象,即:方法内部看到的this

    public synchronizd int getBean() {
        return new Integer(0);
    }
    

    静态方法若使用synchronize修饰后,那么该方法一定具有同步效果.

    如果需要锁静态资源, 则所对象应该写: 类名.class

    4. 死锁现象 (了解)

    当多个线程都持有自己的锁,但是都等对方先释放锁时就会出现"僵持"的情况,使得所有线程进入阻塞状态.这个现象,称为死锁.

    死锁代码案例:

    public class Dead_Syn {
        public static void main(String[] args) {
            Test t = new Test();
    
            new Thread(){
                public void run() {  // A线程
                    t.methodA();
                }
            }.start();
    
            new Thread(){
                public void run() {  // B线程
                    t.methodB();
                }
            }.start();
        }
    }
    
    class Test {
        private Object oa = new Object(); // A锁
        private Object ob = new Object(); // B锁
    
        public void methodA() {
            System.out.println("得到oa锁");
            synchronized (oa) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("A方法-oa锁内部");
                methodB(); // 调用B方法
            }
            System.out.println("释放oa锁");
        }
    
        public void methodB() {
            System.out.println("得到ob锁");
            synchronized (ob) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("B方法-ob锁内部");
                methodA(); // 调用A方法
            }
            System.out.println("释放ob锁");
        }
    }
    

    控制台输出 (输出后程序一直没有结束, 锁一直没有释放!)

    得到oa锁
    得到ob锁
    B方法-ob锁内部
    A方法-oa锁内部
    得到oa锁
    得到ob锁
    
  • 相关阅读:
    在VC6.0中虚函数的实现原理
    札记Microsoft基本类库应用程序框架
    typedef用法剖析
    申请成功记录记录
    vc++6.0环境中swap函数
    ubuntu12.04 安装JDK7
    N皇后问题的位运算求解——目前最快的方法
    Linux常用命令小结
    Ubuntu添加自己的桌面快捷方式
    C++静态成员函数小结(转)
  • 原文地址:https://www.cnblogs.com/zpKang/p/12943767.html
Copyright © 2011-2022 走看看