您的位置:首页 > 编程语言 > Java开发

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

2016-12-18 15:08 429 查看
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是线程不安全的

    

        
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: