java 多线程学习笔记2-同步代码块,死锁

来源:互联网 发布:淘宝买家诈骗怎么办 编辑:程序博客网 时间:2024/06/11 17:17
1、多线程-同步代码块:synchronized


    当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步。
    如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码。
    
    synchronized关键字加上一个锁对象就可以同步代码,这个锁对象可以是任意的一个对象,只要求是同一个就行。
    
    例如:
        class Printer {
            Demo d = new Demo();
            public static void print1() {
                synchronized(d){
                    System.out.print("你");
                    System.out.print("好");
                    System.out.print("呀");
                    System.out.print("\r\n");
                }
            }
            public static void print2() {
                synchronized(d){
                    System.out.print("C");
                    System.out.print("S");
                    System.out.print("D");
                    System.out.print("N");
                    System.out.print("\r\n");
                }
            }
        }
        
        class Demo{              //创建一个任意的class,用来做锁对象
            public Demo(){}
        }
        
        现在在主函数里面创建2条线程执行:如果不加synchronized(d),可能输出print1 和print2就会出现乱序的问题(你好呀CS)。
            final Printer p =  new Printer();
            new Thread(){
                public void run(){  //重写Thread类里面的run方法
                    p.print1();
                }
            }.start();   //启动一个线程
            new Thread(){
                public void run(){  //重写Thread类里面的run方法
                    p.print1();
                }
            }.start();   //启动第二个线程
        
2、多线程-同步方法:synchronized
    使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的
        
    例如:
        class Printer {
            public static synchronized void print1() {//这里的锁对象就是Printer.class(字节码对象) ,锁对象可以是任意的,但必须是同一把锁
                System.out.print("你");
                System.out.print("好");
                System.out.print("呀");
                System.out.print("\r\n");
            }
            public static void print2() {
                synchronized(Printer.class){ //这里使用Printer.class(字节码对象)对象作为锁对象
                    System.out.print("C");
                    System.out.print("S");
                    System.out.print("D");
                    System.out.print("N");
                    System.out.print("\r\n");
                }
            }
        }
        
        注意:
        非静态同步函数的锁是:this (因为创建的对象是同一个,此时的this就代表new的那个对象)
静态static的同步函数的锁是:字节码对象(因为使用 类名.方法 调用 ,类名是同一个)
        
        
3、多线程-线程安全:
    多线程并发操作同一数据时, 就有可能出现线程安全问题,使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作
        class TicketsSeller extends Thread {
            private static int tickets = 100;//定义一个私有静态变量
            static Object obj = new Object();//定义一个锁对象
            public TicketsSeller() {
                super();
                
            }
            public TicketsSeller(String name) {
                super(name);
            }
            public void run() {
                while(true) {
                    synchronized(obj) {//如果没有锁的话,就可能出现多个线程同时操作了tickets这个变量,导致if多次判断0后,还进行了--操作,导致负号票出现
                        if(tickets <= 0) 
                            break;
                        System.out.println(getName() + "...这是第" + tickets-- + "号票");
                    }
                }
            }
        }
        
        //伪代码,创建4个线程调用
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    
3、多线程-死锁:
    多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁,所以尽量不要嵌套使用。
    
        private static String s1 = "left";//定义一个锁对象s1
        private static String s2 = "right";//定义一个锁对象s2
        public static void main(String[] args) {
            new Thread() {
                public void run() {
                    while(true) {
                        synchronized(s1) {
                            System.out.println(getName() + "get" + s1 + "wait" + s2);
                            synchronized(s2) {                                              //有可能执行到这个地方的时候,s2被下面线程使用,未释放,就拿不到s2了
                                System.out.println(getName() + "get" + s2 + "OK");
                            }
                        }
                    }
                }
            }.start();
            
            new Thread() {
                public void run() {
                    while(true) {
                        synchronized(s2) {
                            System.out.println(getName() + "get" + s2 + "wait" + s1);
                            synchronized(s1) {                                              //执行到这个地方,s1被上面线程使用,未释放,线程就一直卡在这了
                                System.out.println(getName() + "get" + s1 + "OK");
                            }
                        }
                    }
                }
            }.start();
        }
    
    
4、多线程-常用线程安全类有哪些:看源码,有synchronized修饰的方法或代码块就是线程安全的
    Vector是线程安全的,ArrayList是线程不安全的
StringBuffer是线程安全的,StringBuilder是线程不安全的
Hashtable是线程安全的,HashMap是线程不安全的
    
        
0 0
原创粉丝点击