Java自学课程笔记8

2021年3月2日20点21分
JAVA自学课程笔记8:

    synchronized(同步)修饰代码块:
        格式:
            synchronized(object aa){
                //同步代码块
            }

        含义:判断aa是否已经被其他线程霸占(术语:锁定),如果发现已经被其他线程霸占。则当前线程陷入等待中,如果发现aa没有被其他线程霸占,则当前线程霸占在aa对象,并执行语句内的同步代码块在当前线程执行同步代码块代码时,其他线程将无法再执行同步代码块的代码(因为当前线程已经霸占了aa对象),当前线程执行完同步代码块的代码后,会自动释放对aa对象的霸占,此时其他线程会相互竞争对aa的霸占,最终CPU会选择其中的某个线程执行。霸占住的那个对象术语叫:监听器。

        最终导致的结果是:一个线程正在操作某资源的时候,将不允许其它线程操作该资源,即一次只允许一个线程处理该资源。

        火车买票程序:
            Test1:
                class A implements Runnable{
                    public static int tickets = 100;

                    public void run(){
                        while(true){
                            if(tickets > 0){
                                System.out.printf("%s线程正在卖出第%d张票", Thread.currentThread().getName(), tickets);
                                tickets --;
                            }else{
                                break;
                            }
                        }
                    }
                }

                public class Test1{
                    public static void main(String[] args){
                        A aa1 =  new A();
                        Thread t1 = new Thread(aa1);
                        t1.start();

                        A aa2 = new A();
                        Thread t2 = new Thread(aa2);
                        t2.start();
                    }
                }
            //虽然用的是static修饰的tickets,但是还是会在执行语句时发生落差,一个对象在不同线程被同时执行且产生时间差,例如1号线程在卖第99张票时,2号线程已经在卖第94张票了,假如正好下一次轮到了1号线程卖,就卖到了第93张。同一个对象被两个线程同时占用,应发程序bug。
                
            Test2:
                class A implements Runnable{
                    public static int tickets = 100;
                    String str = new String("我是一个字符对象!");

                    public void run(){
                        while(true){
                            synchronized(str){
                                if(tickets > 0){
                                    System.out.printf("%s线程正在卖出第%d张票\n", Thread.currentThread().getName(), tickets);

                                    tickets --;
                                }else{
                                    break;
                                }
                            }
                        }
                    }
                }

                public class Test2{
                    public static void main(String[] args){
                        A aa = new A();
                        Thread t1 = new Thread(aa);
                        t1.start();

                        Thread t2 = new Thread(aa);
                        t2.start();
                    }
                }


            synchronized修饰一个方法时,实际霸占的是该方法的this指针所指的对象(即synchronized修饰一个方法时,实际霸占的是正在调用该方法的对象)当一个线程进入这个方法后,这个方法的大门就会暂时关闭(不许其他线程进入)直到这个线程走出这个方法后,该方法的大门才会敞开。当然,这个关闭只是对于该类的当前实例有效,多个实例的对象仍然可以同时执行。若Test2的run()方法用synchronized修饰,运行结果会是永远只有一个线程在卖票。
    

    生产和消费程序:
        class SynStack{
            private int cnt =  0;
            private char[] data = new char[6];

            public synchronized void push(char c){
                while(cnt==data.length){
                    try{
                        this.wait();
                    }catch(InterruptedException e){}
                }
                this.notify();

                data[cnt] = c;
                cnt++;
                System.out.println("produced    #: "+c);
            }

            public synchronized char pop(){
                char c;

                while(cnt==0){
                    try{
                        this.wait();
                    }catch(InterruptedException e){}
                }
                this.notify();
                cnt--;
                System.out.println("consumed    *: "+data[cnt]);
                return data[cnt];
            }
        }


        class Producer implements Runnable{
            private SynStack ss = null;

            public Producer(SynStack ss){
                this.ss = ss;
            }
            
            public void run(){
                char c;

                for(int i=0; i<20; ++i){
                    c = (char)('1'+i);
                    ss.push(c);
                }
            }
        }


        class Consumer implements Runnable{
            private SynStack ss = null;

            public Consumer(SynStack ss){
                this.ss = ss;
            }

            public void run(){
                for(int i=0; i<20; ++i){
                    try{
                        Thread.sleep(2000);
                    }catch(InterruptedException e){}

                    ss.pop();
                }
            }
        }


        public class test1{
            public static void main(String[] args){
                SynStack ss = new SynStack();
                Producer p = new Producer(ss);
                Consumer c = new Consumer(ss);
                Thread t1 = new Thread(p);
                t1.start();

                Thread t2 = new Thread(c);
                t2.start();
            }
        }
    //满足一个线程消费,另外一个线程生产且具有同步性。

 

posted @ 2021-04-12 14:43  katachip  阅读(54)  评论(0编辑  收藏  举报