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

      

    * 1.什么情况下需要同步
    * 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
    * 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
    * 2.同步代码块
    * 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
    * 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

    class Printer {
    Demo d = new Demo();
    public static void print1() {
    synchronized(d){    //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
    System.out.print("a");
    System.out.print("b");
    System.out.print("c");
    System.out.print("d");
    System.out.print("e");
    System.out.print("
    ");
    }
    }
    
    public static void print2() {    
    synchronized(d){    
    System.out.print("1");
    System.out.print("2");
    System.out.print("3");
    System.out.print("4");
    System.out.print("
    ");
    }
    }
    }
        /**
         * @param args
         * 同步代码块
         */
        public static void main(String[] args) {
            final Printer p = new Printer();
            
            new Thread() {
                public void run() {
                    while(true) {
                        p.print1();
                    }
                }
            }.start();
            
            new Thread() {
                public void run() {
                    while(true) {
                        p.print2();
                    }
                }
            }.start();
        }

    =======================================================================

    同步方法
    * 使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

    class Printer {
    public static void print1() {
      synchronized(Printer.class)   { //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象        静态方法锁对象是字节码对象!!!
    System.out.print("1");
    System.out.print("2");
    System.out.print("3");
    System.out.print("4");
    System.out.print("5");
    System.out.print(" ");
    }
    }


    /*
    * 非静态同步函数的锁是:this
    * 静态的同步函数的锁是:字节码对象
    */
    public static synchronized void print2() {
    System.out.print("a");
    System.out.print("b");
    System.out.print("c");
    System.out.print("d");
    System.out.print(" ");
    }
    }

    =================================================

    线程安全问题
    * 多线程并发操作同一数据时, 就有可能出现线程安全问题
    * 使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作

        /**
         * 需求:铁路售票,一共100张,通过四个窗口卖完.
         */
        public static void main(String[] args) {
            new Ticket().start();
            new Ticket().start();
            new Ticket().start();
            new Ticket().start();
        }
    
    }
    
    class Ticket extends Thread {
        private static int ticket = 100;
        //private static Object obj = new Object();        //如果用引用数据类型成员变量当作锁对象,必须是静态的
        public void run() {
            while(true) {
                synchronized(Ticket.class) {
                    if(ticket <= 0) {
                        break;
                    }
                    try {
                        Thread.sleep(10);                //线程1睡,线程2睡,线程3睡,线程4睡
                    } catch (InterruptedException e) {
                        
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "...这是第" + ticket-- + "号票");
                }
            }
        }
    }
     


    火车站卖票的例子用实现Runnable接口


    /** * @param args * 火车站卖票的例子用实现Runnable接口 */ public static void main(String[] args) { MyTicket mt = new MyTicket(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); /*Thread t1 = new Thread(mt); //多次启动一个线程是非法的 t1.start(); t1.start(); t1.start(); t1.start();*/ } } class MyTicket implements Runnable { private int tickets = 100; @Override public void run() { while(true) { synchronized(this) { if(tickets <= 0) { break; } try { Thread.sleep(10); //线程1睡,线程2睡,线程3睡,线程4睡 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "...这是第" + tickets-- + "号票"); } } } }

    =========================================================================

    死锁
    * 多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁
    * 尽量不要嵌套使用

    private static String s1 = "筷子左";
                private static String s2 = "筷子右";
                public static void main(String[] args) {
                    new Thread() {
                        public void run() {
                            while(true) {
                                synchronized(s1) {
                                    System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
                                    synchronized(s2) {
                                        System.out.println(getName() + "...拿到" + s2 + "开吃");
                                    }
                                }
                            }
                        }
                    }.start();
                    
                    new Thread() {
                        public void run() {
                            while(true) {
                                synchronized(s2) {
                                    System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
                                    synchronized(s1) {
                                        System.out.println(getName() + "...拿到" + s1 + "开吃");
                                    }
                                }
                            }
                        }
                    }.start();
                }

    进程一执行到  

    synchronized(s1){
    System.out.println(getName()+"获取"+s1+"等待"+s2);  

    此时  , 进程二开始运行 

    synchronized(s2) {
    System.out.println(getName() + "...拿到" + s2 + "等待" + s1);

    进程一等待s2 , 进程二等待拿s1.

     ==============================================================

     看源码:Vector,StringBuffer,Hashtable,Collections.synchroinzed(xxx

    * Vector是线程安全的,ArrayList是线程不安全的
    * StringBuffer是线程安全的,StringBuilder是线程不安全的
    * Hashtable是线程安全的,HashMap是线程不安全的

  • 相关阅读:
    在Oracle中计算两个日期间隔的天数、月数和年数
    洛谷P1182 数列分段 Section II(二分+贪心)
    BZOJ1734 [Usaco2005 feb]Aggressive cows 愤怒的牛(二分答案+贪心)
    分治算法
    洛谷P1031 [NOIP2002]均分纸牌
    洛谷P1803 凌乱的yyy / 线段覆盖
    洛谷P1094 [NOIP2007]纪念品分组
    洛谷P1223 排队接水
    洛谷P1208 [USACO1.3]混合牛奶 Mixing Milk
    洛谷P1181 数列分段Section1
  • 原文地址:https://www.cnblogs.com/yimian/p/6565180.html
Copyright © 2011-2022 走看看