zoukankan      html  css  js  c++  java
  • java并发编程之synchronized

    1.多个线程访问同一资源时会产生线程安全问题,因此要实现同步互斥访问资源。

    举例:在购票时,总票数10,售票员1卖一张票票数为9,但在售票员1卖这张票的过程中,售票员2也在卖票其开始读到总票数也为10,卖一张9,然后两个售票员都读到了余票为9的错误的信息。

    2.解决线程安全问题方式:

    (1)synchronized同步方法或同步块(2)lock锁

     在java中,每个对象都有一个锁标记,当线程要访问被synchronized关键字修饰的代码片段时,必须检查该对象的锁是否可用,可用,获得锁,执行代码,释放锁。其他想访问该代码片段没获得该锁的线程就处于自我阻塞状态。
    

    <1>synchronized 同步方法
    未使用synchronized修饰:

    package day03;
    
    import java.util.ArrayList;
    
    /**
     * @author wangpei
     * @version 创建时间:2017年2月10日 上午10:38:22 类说明
     */
    public class Test implements Runnable {
        final InsertData insertData = new InsertData();
    
        public void run() {
            insertData.insert(Thread.currentThread());
    
        }
    
        public static void main(String[] args) {
    
            Test t = new Test();
            new Thread(t, "Thread-0").start();
            new Thread(t, "Thread-1").start();
        }
    }
    
    class InsertData {
        private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    
        public  void insert(Thread thread) {
            for (int i = 0; i < 5; i++) {
                System.out.println(thread.getName() + "在插入数据" + i);
                arrayList.add(i);
            }
        }
    }
    
    

    执行结果:

    Thread-0在插入数据0
    Thread-1在插入数据0
    Thread-1在插入数据1
    Thread-0在插入数据1
    Thread-1在插入数据2
    Thread-0在插入数据2
    Thread-1在插入数据3
    Thread-0在插入数据3
    Thread-1在插入数据4
    Thread-0在插入数据4
    
    线程0和线程1的执行是无序的
    

    使用synchronized:

    class InsertData {
        private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    
        public synchronized void insert(Thread thread) {
            for (int i = 0; i < 5; i++) {
                System.out.println(thread.getName() + "在插入数据" + i);
                arrayList.add(i);
            }
        }
    }
    

    执行结果:

    Thread-0在插入数据0
    Thread-0在插入数据1
    Thread-0在插入数据2
    Thread-0在插入数据3
    Thread-0在插入数据4
    Thread-1在插入数据0
    Thread-1在插入数据1
    Thread-1在插入数据2
    Thread-1在插入数据3
    Thread-1在插入数据4
    
    Thread-0先获得对象的锁然后,执行代码插入数据,然后释放锁,接着Thread-1执行。0,1线程是顺序执行的。
    

    注意:
    (1)在并发访问时,要将资源域设置为private,防止其它线程直接操作该资源。
    (2)当一个线程在访问该对象的synchronized修饰的方法时,其它线程可以访问该对象的非synchronized修饰的方法,但不可以访问该对象的其他被synchronized修饰的方法。(对象锁只有一个,已经在使用中,必须获得锁在可以访问synchronized修饰的方法)
    例子:
    对于对象object:有方法
    synchronized void s1(){},
    synchronized void s2(){},
    void s3(){},
    当线程Thread-0获得锁而操作s1方法时,线程Thread-1可以访问s3方法,不可以访问s2方法。
    <2>synchronized 同步代码块

    形式:
    synchronized(对象this(当前对象)/属性){}

    class InsertData {
        private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    
        public  void insert(Thread thread) {
            synchronized(arrayList){
            for (int i = 0; i < 5; i++) {
                System.out.println(thread.getName() + "在插入数据" + i);
    
                    arrayList.add(i);
            }
        }
        }
    }

    同步代码块,比同步方法范围小,在执行时访问线程Thread-0访问a方法中同步代码块中的内容,而没获得锁的Thread-1仍旧可访问a方法中的非synchronized代码快。

    <3>类锁
    针对每个类,也有一个锁(作为class对象的一部分)。synchronized static修饰的方法可以在类范围内防止对static数据的并发访问。

  • 相关阅读:
    CSS3 box-shadow(阴影使用)
    缩小窗口时CSS背景图出现右侧空白BUG的解决方法
    html打开个人QQ聊天页面
    帮助你实现元素动画的6款插件
    给出两个颜色,计算中间颜色返回数组
    名字首字母
    自适应网页设计
    tab切换jquery代码
    改变上传文件样式
    剑指offer 面试16题
  • 原文地址:https://www.cnblogs.com/wangxiaopei/p/8551256.html
Copyright © 2011-2022 走看看