多线程基础4 同步与通信

 1.什么情况下需要同步 当多线程并发执行同一代码时 希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步. 


 2.同步代码块 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的


public class TestMain {
    public static void print1() {
        //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
        synchronized(String.class){
            System.out.print("1");
            System.out.print("2");
        }
    }

    //非静态同步函数的锁是:this   (非静态方法已创建实例化对象后调用的)
    public synchronized void print2() {
        System.out.print("1");
        System.out.print("2");
    }

   // 静态的同步函数的锁是:字节码对象.class   (静态是初始化时形成的所以 是字节码对象)
    public static synchronized void print3() {
        System.out.print("1");
        System.out.print("2");
    }

}

多线程(两个线程间的通信)

  • 1.什么时候需要通信 * 多个线程并发执行时, 在默认情况下CPU是随机切换线程的 * 如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次打印
  • 2.怎么通信 * 如果希望线程等待, 就调用wait() * 如果希望唤醒等待的线程, 就调用notify(); * 这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

 

public class Demo1_Notify {



    /**

     * @param args

     * 等待唤醒机制

     */

    public static void main(String[] args) {

        final Printer p = new Printer();



        new Thread() {

            public void run() {

                while(true) {

                    try {

                        p.print1();

                    } catch (InterruptedException e) {



                        e.printStackTrace();

                    }

                }

            }

        }.start();



        new Thread() {

            public void run() {

                while(true) {

                    try {

                        p.print2();

                    } catch (InterruptedException e) {



                        e.printStackTrace();

                    }

                }

            }

        }.start();

    }



}



//等待唤醒机制

class Printer {

    private int flag = 1;

    public void print1() throws InterruptedException {

        synchronized(this) {

            if(flag != 1) {

                this.wait();               //当前线程等待

            }

            System.out.print("方法一");

            System.out.print("\r\n");

            flag = 2;

            this.notify();                //随机唤醒单个等待的线程

        }

    }



    public void print2() throws InterruptedException {

        synchronized(this) {

            if(flag != 2) {

                this.wait();

            }

            System.out.print("方法2");

            System.out.print("\r\n");

            flag = 1;

            this.notify();

        }

    }

}

 

多线程(三个或三个以上间的线程通信)

多个线程通信的问题 * notify()方法是随机唤醒一个线程 * notifyAll()方法是唤醒所有线程 * JDK5之前无法唤醒指定的一个线程 * 如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件

public class Demo2_NotifyAll {



    /**

     * @param args

     */

    public static void main(String[] args) {

        final Printer2 p = new Printer2();

        new Thread() {

            public void run() {

                while(true) {

                    try {

                        p.print1();

                    } catch (InterruptedException e) {



                        e.printStackTrace();

                    }

                }

            }

        }.start();



        new Thread() {

            public void run() {

                while(true) {

                    try {

                        p.print2();

                    } catch (InterruptedException e) {



                        e.printStackTrace();

                    }

                }

            }

        }.start();



        new Thread() {

            public void run() {

                while(true) {

                    try {

                        p.print3();

                    } catch (InterruptedException e) {



                        e.printStackTrace();

                    }

                }

            }

        }.start();

    }



}


1,在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法

2,为什么wait方法和notify方法定义在Object这类中?

     因为锁对象可以是任意对象,Object是所有的类的基类,所以wait方法和notify方法需要定义在Object这个类中

3,sleep方法和wait方法的区别?

  a,sleep方法必须传入参数,参数就是时间,时间到了自动醒来wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待

  b,sleep方法在同步函数或同步代码块中,不释放锁,睡着了也抱着锁睡wait方法在同步函数或者同步代码块中,释放锁

 

class Printer2 {

    private int flag = 1;

    public void print1() throws InterruptedException {

        synchronized(this) {

            while(flag != 1) {

                this.wait();               //当前线程等待

            }

            System.out.print("方法一");

         

            System.out.print("\r\n");

            flag = 2;

            //this.notify();                  //随机唤醒单个等待的线程

            this.notifyAll();

        }

    }



    public void print2() throws InterruptedException {

        synchronized(this) {

            while(flag != 2) {

                this.wait();               //线程2在此等待

            }

            System.out.print("方法2");

             System.out.print("\r\n");

            flag = 3;

            //this.notify();

            this.notifyAll();

        }

    }



    public void print3() throws InterruptedException {

        synchronized(this) {

            while(flag != 3) {

                this.wait();                  //线程3在此等待,if语句是在哪里等待,就在哪里起来

                //while循环是循环判断,每次都会判断标记

            }

            System.out.print("方法三");

            System.out.print("\r\n");

            flag = 1;

            //this.notify();

            this.notifyAll();

        }

    }

}

消费者与生产者


//消费者
synchronized(对象) {

		if(货物==null)
		对象.wait();
	
	    对应的处理逻辑
}

//生产者

synchronized(对象) {
	产生货物
	对象.notifyAll();
}

线程间的通信还可以使用 管道输入/输出流

public class Piped {
    public static void main(String[] args) throws Exception {
        PipedWriter out = new PipedWriter();
        PipedReader in = new PipedReader();
// 将输出流和输入流进行连接,否则在使用时会抛出IOException
        out.connect(in);
        Thread printThread = new Thread(new Print(in), "PrintThread");
        printThread.start();
        int receive = 0;
        try {
            while ((receive = System.in.read()) != -1) {
                out.write(receive);
            }
        } finally {
            out.close();
        }
    }

    static class Print implements Runnable {
        private PipedReader in;

        public Print(PipedReader in) {
            this.in = in;
        }

        public void run() {
            int receive = 0;
            try {
                while ((receive = in.read()) != -1) {
                    System.out.print((char) receive);
                }
            } catch (IOException ex) {
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_25825923/article/details/82774631