• 6※、线程同步、同步锁、同步代码块的使用、同步锁释放的时机、ReentrantLock可重入锁


    1、※线程的同步:(要确保对象锁是一致的)

    同步的概念:确保代码执行的有序性、事务执行的完整性,数据共享的可靠性和正确性;在多线程并发的情况下,使得在同一个时间点只能有一个线程访问同步方法或同步代码块
    同步方法:使用this作为当前同步方法的同步锁,只有获得此对象锁的线程才能执行同步方法中的操作
    this是调用当前方法的对象的引用
    同步代码块:可以灵活定义同步修饰的代码区域,自定义同步锁,也能实现同步代码块的嵌套

    1、未使用同步锁的抢票

    注意:会出现同一张火车票给多个线程获取
    现实生活中这种情况是不允许出现
    京东抢到了序号为;100的车型
    飞猪抢到了序号为;100的车型
    智行抢到了序号为;100的车型
    智行抢到了序号为;97的车型
    智行抢到了序号为;96的车型
    飞猪抢到了序号为;98的车型

    /**
     * @author Lantzrung
     * @date 2022年8月5日
     * @Description
     */
    package com.day0805sileo01;
    
    public class TicketTask2 implements Runnable {
    
        
        // 测试操作
        public static void main(String[] args) {
    	//
    	TicketTask2 task = new TicketTask2();
    	// 1、创建线程的对象
    	Thread jingdong = new Thread(task, "京东");
    	Thread zhixing = new Thread(task, "智行");
    	Thread feizhu = new Thread(task, "飞猪");
    	// 2、启动线程
    	jingdong.start();
    	zhixing.start();
    	feizhu.start();
        }
    
        // 定义票数 【资源共享】
        public int nums = 100;
    
        // 实现抢票操作
        @Override
        public void run() {
    	// 抢票--循环操作
    	while (nums > 0) {
    	    // 获取线程名称
    	    String name = Thread.currentThread().getName();
    	    System.out.println(name + "抢到了序号为;" + nums + "的车型");
    	    // 票数--
    	    nums--;
    
    	}
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    2、使用了同步锁的抢票

    调用了sleep方法后,线程会进入阻塞状态,释放了cpu执行权,但是没有释放对象锁

    /**
     * @author Lantzrung
     * @date 2022年8月5日
     * @Description
     */
    package com.day0805sileo01;
    
    public class TicketTask implements Runnable {
        // 测试操作
        public static void main(String[] args) {
    	// 只有一个任务对象 (task的对象锁)
    	TicketTask task = new TicketTask();
    	// 1、创建线程的对象
    	Thread jingdong = new Thread(task, "京东");
    	Thread zhixing = new Thread(task, "智行");
    	Thread feizhu = new Thread(task, "飞猪");
    	// 2、启动线程
    	jingdong.start();
    	zhixing.start();
    	feizhu.start();
    //	京东抢到了序号为:100的车票
    //	飞猪抢到了序号为:99的车票
    //	智行抢到了序号为:98的车票
    //	京东抢到了序号为:97的车票
    //	飞猪抢到了序号为:96的车票
    //	智行抢到了序号为:95的车票
    //	飞猪抢到了序号为:94的车票
    //	京东抢到了序号为:93的车票
    //	智行抢到了序号为:92的车票
    //	飞猪抢到了序号为:91的车票
    //	京东抢到了序号为:90的车票
    //	智行抢到了序号为:89的车票
    //	京东抢到了序号为:88的车票
    //	飞猪抢到了序号为:87的车票
    //	智行抢到了序号为:86的车票
        }
    
        // 定义票数 【资源共享】
        public int nums = 100;
    
        // 实现抢票操作
        @Override
        public void run() {
    //	saleTicket();// 调用方法
    	// 注意:放在这里只会执行这几个
    //	100抢到了序号为:100的车票
    //	99抢到了序号为:99的车票
    //	98抢到了序号为:98的车票
    	// 抢票--循环操作
    	while (nums > 0) {
    	    // 睡眠
    	    try {
    		saleTicket();// 调用方法
    		Thread.sleep(20);
    	    } catch (InterruptedException e) {
    		e.printStackTrace();
    	    }
    	}
        }
        // 定义一个同步方法【限定在同一个时间点,只能有一个线程执行操作】
        // 同步锁(对象锁):只有拿到了该对象锁的线程才能执行这个同步操作(this--作为同步方法的对象锁)
        // 注意:在同步方法中,循环操作中睡眠不会释放对象锁
    //    OPEN2
        public synchronized void saleTicket() {
    	if (nums > 0) {
    	    // 获取线程名称
    	    String name = Thread.currentThread().getName();
    	    System.out.println(name + "抢到了序号为:" + nums + "的车票");
    	    // 票数--
    	    nums--;
    	}
        }
    
    //     OPEN1: 这个操作是一直循环输出 京东线程 因为使用的是while循环 就算加上睡眠操作还是会一直输出该京东线程的   
    //    public synchronized void saleTicket() { 
    //	while (nums > 0) {
    //	    // 获取线程名称
    //	    String name = Thread.currentThread().getName();
    //	    System.out.println(name + "抢到了序号为;" + nums + "的车型");
    //	    // 票数--
    //	    nums--; 
    //    // 睡眠
    //    try {
    //	Thread.sleep(20);
    //    } catch (InterruptedException e) {
    //	e.printStackTrace();
    //    } 
    		京东抢到了序号为;25的车型
    		京东抢到了序号为;24的车型
    		京东抢到了序号为;23的车型
    		京东抢到了序号为;22的车型
    		京东抢到了序号为;21的车型
    		京东抢到了序号为;20的车型
    		京东抢到了序号为;19的车型
    		京东抢到了序号为;18的车型
    		京东抢到了序号为;17的车型
    		京东抢到了序号为;16的车型
    		京东抢到了序号为;15的车型
    		京东抢到了序号为;14的车型
    		京东抢到了序号为;13的车型
    		京东抢到了序号为;12的车型
    		京东抢到了序号为;11的车型
    		京东抢到了序号为;10的车型
    		京东抢到了序号为;9的车型
    		京东抢到了序号为;8的车型
    		京东抢到了序号为;7的车型
    		京东抢到了序号为;6的车型
    		京东抢到了序号为;5的车型
    		京东抢到了序号为;4的车型
    		京东抢到了序号为;3的车型
    		京东抢到了序号为;2的车型
    		京东抢到了序号为;1的车型
    //	}
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    3、线程-同步代码块的使用

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    public class TicketTask implements Runnable {
        public static void main(String[] args) {
    	// 创建票数对象
    	TicketTask task = new TicketTask();
    	// 创建线程对象
    	Thread jd = new Thread(task, "京东");
    	Thread zx = new Thread(task, "智行");
    	Thread fz = new Thread(task, "飞猪");
    	// 启动线程
    	jd.start();
    	zx.start();
    	fz.start();
        task.test();
    //	test
    //	飞猪抢到了序号为:100
    //	智行抢到了序号为:99
    //	京东抢到了序号为:98
    //	京东抢到了序号为:97
    //	智行抢到了序号为:96
    //	飞猪抢到了序号为:95
        }
    
        // 定义票数
        public int nums = 100;
    
        // 实现抢票操作
        @Override
        public void run() {
    	// 抢票--循环操作
    	while (nums > 0) {
    	    // 同步代码块【同步监视的区域】 【对象锁是一个对象即可】
    //	    synchronized (this) {
    		synchronized ("a") {
    		if (nums > 0) {
    		    // 获取线程名称
    		    String name = Thread.currentThread().getName();
    		    System.out.println(name + "抢到了序号为:" + nums);
    		    // 票数--
    		    nums--;
    		}
    	    }
    	    // 睡眠
    	    try {
    		Thread.sleep(20);
    	    } catch (InterruptedException e) {
    		e.printStackTrace();
    	    }
    	}
        }
        // 同步代码块可以跨方法、跨类进行监听
        public void test() { 
    	synchronized ("a") {
    	    System.out.println("test");
    	}
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    4、同步方法和代码块的区别

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    public class TicketDemo {
        // this
        public synchronized void demo() {
    	System.out.println("执行demo操作");
        }
    
        // 嵌套上锁 【同步代码块】
        public void test1() {
    	synchronized ("a") {
    	    System.out.println("执行操作a");
    	    synchronized ("b") {
    		System.out.println("执行操作b");
    	    }
    	}
        }
    
        // 两个类型不一样的,因为一个"a"常量池里面的 一个重新new出来的对象String 两个的情况不一样的
        public void drawMoney() {
    	synchronized ("a") {
    	}
    	synchronized (new String("a")) {
    	}
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    5、同步锁释放的时机

    思考:同步锁释放的时机

    –1、正常执行完同步代码
    –2、遇到return、break结合标签时
    –3、抛出异常、出现错误
    –4、当线程进行等待时,调用了wait()方法

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    import java.util.Iterator;
    
    import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID;
    
    public class TestBlock {
    
        public static void main(String[] args) {
    	// 创建对象为
    	TestBlock b = new TestBlock();
    	// 1、创建线程
    	Thread t1 = new Thread(new Runnable() {
    	    @Override
    	    public void run() {
    		b.test1();
    	    }
    	});
    	Thread t2 = new Thread(new Runnable() {
    
    	    @Override
    	    public void run() {
    		b.test2();
    	    }
    	});
    	// 启动线程
    	t1.start();
    	t2.start();
        }
    
        public synchronized void test1() {
    //	进入test1
    //	进入test2
    	System.out.println("进入test1");
    
    	// 时机4:当线程进行等待时,调用了wait()方法
    	// 注意:这里是线程进去等待的状态,而不会释放对象锁
    	for (int i = 1; i <= 5; i++) {
    	    if (i == 3) {
    		try {
    		    wait();// 注意:这里是线程进去等待的状态,而不会释放对象锁
    		} catch (InterruptedException e) {
    		    e.printStackTrace();
    		}
    	    }
    	}
    
    	// 时机3:为抛出异常、出现错误
    	// 直接跳出异常体,不执行里面异常体内的代码块
    //	进入test1
    //	进入test2
    //	Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
    //		at com.day0806.TestBlock.test1(TestBlock.java:45)
    //		at com.day0806.TestBlock$1.run(TestBlock.java:21)
    //		at java.lang.Thread.run(Thread.java:745)
    
    //	for (int i = 1; i <= 5; i++) {
    //	    try {
    //		// 出现异常
    //		if (i == 3) {
    //		    int item = 3 / 0;
    //		}
    //		Thread.sleep(1000);
    //	    } catch (InterruptedException e) {
    //		e.printStackTrace();
    //	    }
    //	}
    
    //	// 时机2:遇到return、break结合标签时
    //	for (int i = 1; i <= 5; i++) {
    //	    try {
    //		//
    //		if (i == 2) {
    //		    break;// break和return都是执行输出一次 test1.......
    		    continue;// continue执行4次 test1.......		  
    //		}
    //		System.out.println("test1.......");
    //		Thread.sleep(1000);
    //	    } catch (InterruptedException e) {
    //		e.printStackTrace();
    //	    }
    //	}
    
    	// 时机1:正常执行完同步代码
    //	for (int i = 1; i <= 5; i++) {
    //	    try {
    //		Thread.sleep(1000);
    //		System.out.println("test...");
    //	    } catch (InterruptedException e) {
    //		e.printStackTrace();
    //	    }
    //	}
    	// open1:
    //	进入test1
    //	test...
    //	test...
    //	test...
    //	test...
    //	test...
    //	进入test2
        }
    
        public synchronized void test2() {
    	System.out.println("进入test2");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    练习:多线程生产手机

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    // 手机生产类
    public class PhoneProducer {
    
        public static void main(String[] args) {
    	// 提供生产类的对象
    	PhoneProducer producer = new PhoneProducer();
    	// run任务类
    	Runnable task = new Runnable() {
    
    	    @Override
    	    public void run() {
    		// 循环生产手机
    		while (producer.num > 0) {
    		    producer.produceint();
    		    // 延迟
    		    try {
    			Thread.sleep(50);
    		    } catch (InterruptedException e) {
    			e.printStackTrace();
    		    }
    		}
    	    }
    	};
    	// 创建多个工人【线程】
    	Thread t1 = new Thread(task, "翠花");
    	Thread t2 = new Thread(task, "如花");
    	Thread t3 = new Thread(task, "小平");
    	// 开始生产
    	t1.start();
    	t2.start();
    	t3.start();
        }
    
        // 限定每天100台
        int num = 100;
    
        // 提供一个生产方法【this对象要唯一】
        public synchronized void produceint() {
    	if (num >= 1) {
    	    //
    	    String name = Thread.currentThread().getName();
    	    //
    	    System.out.printf("%s生产了No.xs%d的手机!\n", name, num);
    	    //
    	    num--;
    	}
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    2※、ReentrantLock可重入锁:【优点:可以非阻塞操作,定义操作逻辑】

    –可重入锁特点:
    (A) 上锁次数
    [1] lock.lock() 可以上锁多次 [可重入]
    [2] 你想完全解锁, 必须解够上锁的次数。
    解锁次数 == 上锁次数
    (B) 上锁与解锁
    [1] 你可以在任意位置上锁, 也可以任意位置解锁。
    [2] 但是 上锁与解锁的线程必须保证是同一个线程, 否则, 会发生线程处理状态异常。
    © 尝试上锁tryLock(),如果有获取到锁则上锁并且操作,没有获取到锁,也不会阻塞线程,也可以设置超时时间
    (D) 可以设置公平锁和非公平锁【默认是非公平】
    非公平锁:抢夺式,谁抢到就谁执行【可以先直接抢,后排队】
    公平锁:每个线程的获取资源的几率是一样的【直接排队】

    – 注意事项: [1] 确保lock是同一个对象锁 [2] 防范异常的发生, 发现有如下的问题, 因为发生一个异常,
    导致锁无法释放。
    应该采取某个策略来防止类似的事情发生。
    引入异常处理机制 try{ } catch(){ }finally{ }
    将 lock.unlock(); 放入 finally 中。 [3] 为了防止 Lock 引用被修改, 请将 Lock 定为 final 最终变量。
    – 使用场景: [1] 需要灵活上锁 [2] 不想在上锁时阻塞,可以定义非阻塞的操作逻辑 [3] 需要设置为公平锁时

    1、可重入锁的使用

    注意:要是单是上锁的话,会比平时执行的效率慢一点
    注意:加上了unlock就会回到平时执行效率

    (A) 上锁次数
    [1] lock.lock() 可以上锁多次 [可重入]
    [2] 你想完全解锁, 必须解够上锁的次数。
    解锁次数 == 上锁次数

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReentrantLockDemo {
    
        public static void main(String[] args) {
    	ReentrantLockDemo reenDemo = new ReentrantLockDemo();
    	Runnable take = new Runnable() {
    
    	    @Override
    	    public void run() {
    		while (reenDemo.num > 0) {
    		    reenDemo.produceing();
    		    // 延迟
    		    try {
    			Thread.sleep(50);
    		    } catch (InterruptedException e) {
    			e.printStackTrace();
    		    }
    		}
    	    }
    	};
    	Thread t1 = new Thread(take, "翠花");
    	Thread t2 = new Thread(take, "如花");
    	Thread t3 = new Thread(take, "小平");
    	// 开始生产
    	t1.start();
    	t2.start();
    	t3.start();
    
        }
    
        int num = 100;
    
        // 可重入锁 【确保lock对象是唯一】
        Lock lock = new ReentrantLock();
    
        // 提供一个方法生产方法 【可重入锁】
        public void produceing() {
    	// 上锁
    	lock.lock();// 注意:要是单是上锁的话,会比平时执行的效率慢一点
    	if (num >= 1) {
    	    //
    	    String name = Thread.currentThread().getName();
    	    //
    	    System.out.printf("%s生产了No.xs%d的手机!\n", name, num);
    	    //
    	    num--;
    	}
    	lock.unlock();// 注意:加上了unlock就会回到平时执行效率
        }
    }
    // [同步代码块]
    //    public void produceing() {
    // 	synchronized ("produceing") {
    // 	    if (num >= 1) {
    // 		//
    // 		String name = Thread.currentThread().getName();
    // 		//
    // 		System.out.printf("%s生产了No.xs%d的手机!\n", name, num);
    // 		//
    // 		num--;
    // 	    }
    // 	}
    //     }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    2、可重入锁的注意事项1

        (B) 上锁与解锁
        [1] 你可以在任意位置上锁, 也可以任意位置解锁。
        [2] 但是 上锁与解锁的线程必须保证是同一个线程, 否则, 会发生线程处理状态异常。
        
      open1:
    // 提供一个方法生产方法 【可重入锁】
      open2 :
    // 加上try上后出现多次的异常
    // 认为的异常进行操作
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    /**
     * @author Lantzrung
     * @create 2022-08-06
     * @Description
     */
    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReentrantLockDemo2 {
    
        public static void main(String[] args) {
            ReentrantLockDemo2 reenDemo = new ReentrantLockDemo2();
            Runnable take = new Runnable() {
    
                @Override
                public void run() {
                    while (reenDemo.num > 0) {
                        reenDemo.produceing();
                        // 延迟
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            Thread t1 = new Thread(take, "翠花");
            Thread t2 = new Thread(take, "如花");
            Thread t3 = new Thread(take, "小平");
            // 开始生产
            t1.start();
            t2.start();
            t3.start();
        }
    
        // 限定每天100台的操作
        int num = 100;
    
        // 可重入锁 【确保lock对象是唯一】【注意:出现异常不会释放锁,所以要在finall去释放可重入锁】
        Lock lock = new ReentrantLock();
    
        // open2:
        // 加上try上后出现多次的异常
        // 认为的异常进行操作
    //    public void produceing() {
    //	// 上锁
    //	lock.lock();
    //	try {
    //	    if (num >= 1) {
    //		//
    //		String name = Thread.currentThread().getName();
    //		//
    //		System.out.printf("%s生产了No.xs%d的手机!", name, num);
    //		//
    //		num--;
    //		//
    //		int item = 3 / 0;
    		小平生产了No.xs12的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	java.lang.ArithmeticException: / by zero
    	如花生产了No.xs11的手机!	at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	翠花生产了No.xs10的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	小平生产了No.xs9的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	如花生产了No.xs8的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	小平生产了No.xs7的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	翠花生产了No.xs6的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	如花生产了No.xs5的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	翠花生产了No.xs4的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	小平生产了No.xs3的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	如花生产了No.xs2的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    	翠花生产了No.xs1的手机!java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    //
    //	    }
    //	} catch (Exception e) {
    //	    e.printStackTrace();
    //	} finally {
    //	    // 解锁
    //	    lock.unlock();
    //	}
    //    }
    
    //    open1:
    //    // 提供一个方法生产方法 【可重入锁】
    //    public void produceing() {
    //	// 上锁
    //	lock.lock();
    //	if (num >= 1) {
    //	    //
    //	    String name = Thread.currentThread().getName();
    //	    //
    //	    System.out.printf("%s生产了No.xs%d的手机!\n", name, num);
    //	    //
    //	    num--;
    //	    // open1;人为的异常操作
    //	    // 此操作出现异常后不会释放锁进行后续的操作。
    	    int item = 3 / 0;
    //	    // 翠花生产了No.xs100的手机!
    	    Exception in thread "翠花" java.lang.ArithmeticException: / by zero
    		at com.day0806.ReentrantLockDemo2.produceing(ReentrantLockDemo2.java:58)
    		at com.day0806.ReentrantLockDemo2$1.run(ReentrantLockDemo2.java:20)
    		at java.lang.Thread.run(Thread.java:745)
    //	}
    //	// 解锁
    //	lock.unlock();
    //   }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149

    解一把锁不会输出调用test2的方法,解除两把锁才是正常输出

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0805sil02;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class TestBlock02 {
        public static void main(String[] args) {
     	// 创建对象
     	TestBlock02 b = new TestBlock02();
     	// 1、创建线程
     	Thread t1 = new Thread(new Runnable() {
     	    @Override
     	    public void run() {
     		b.test1();
     	    }
     	});
    
     	t1.start();
     	// 先确保启动线程一 再启动线程二
     	try {
     	    Thread.sleep(100);
     	} catch (InterruptedException e) {
     	    throw new RuntimeException(e);
     	}
     	Thread t2 = new Thread(new Runnable() {
     	    @Override
     	    public void run() {
     		b.test2();
     	    }
     	});
     	t2.start();
         }
        
        // 创建上锁对象
        Lock lock = new ReentrantLock();
    
        // 第一个方法
        public void test1() {
            // 第一次上锁
            lock.lock();
            System.out.println("进入test1方法...");
            // 第二次上锁
            lock.lock();
            // 延迟
            for (int i = 0; i <= 5; i++) {
                try {
                    // 输出
                    System.out.println("test1...");
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // 解第一把锁
            lock.unlock();
            // 解第二把锁
            lock.unlock();
            open1
            // 正常的输出操作是输出这个的
    //        进入test1方法...
    //        test1...
    //        test1...
    //        test1...
    //        test1...
    //        test1...
    //        test1...
    //        进入test2
    
            open2
            // 要是不解除就不会执行test2了
    //        进入test1方法...
    //        test1...
    //        test1...
    //        test1...
    //        test1...
    //        test1...
    //        test1...
    
        }
    
        public void test2() {
            // 上锁
            lock.lock();
            System.out.println("进入test2");
            //  解锁
            lock.unlock();
        }
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    3、可重入锁的注意事项2

    尝试上锁tryLock(),如果有获取到锁则上锁并且操作,没有获取到锁,也不会阻塞线程,也可以设置超时时间

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0805sil02;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class TestBlock3 {
        public static void main(String[] args) {
    	// 创建对象
    	TestBlock3 b = new TestBlock3();
    	// 1、创建线程
    	Thread t1 = new Thread(new Runnable() {
    	    @Override
    	    public void run() {
    		b.test1();
    	    }
    	});
    
    	t1.start();
    	// 先确保启动线程一 再启动线程二
    	try {
    	    Thread.sleep(100);
    	} catch (InterruptedException e) {
    	    throw new RuntimeException(e);
    	}
    	Thread t2 = new Thread(new Runnable() {
    	    @Override
    	    public void run() {
    		b.test2();
    	    }
    	});
    	t2.start();
        }
    
        // 创建上锁对象
        Lock lock = new ReentrantLock();
    
        // 第一个方法
        public void test1() {
    	// 第一次上锁
    	lock.lock();
    	System.out.println("进入test1方法...");
    	// 第二次上锁
    	lock.lock();
    	// 延迟
    	for (int i = 0; i <= 5; i++) {
    	    try {
    		// 输出
    		System.out.println("test1...");
    		Thread.sleep(200);
    	    } catch (InterruptedException e) {
    		throw new RuntimeException(e);
    	    }
    	}
    	// 解第一把锁
    	lock.unlock();
    	// 解第二把锁
    	lock.unlock();
        }
    
        public void test2() {
    	// 尝试获取锁 【非阻塞地获取锁】
    //	open1
    //	进入test1方法...
    //	test1...
    //	进入test2
    //	Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    //		at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
    //		at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
    //		at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
    //		at com.day0805sil02.TestBlock3.test2(TestBlock3.java:70)
    //		at com.day0805sil02.TestBlock3$2.run(TestBlock3.java:33)
    //		at java.lang.Thread.run(Thread.java:745)
    //	test1...
    //	test1...
    //	test1...
    //	test1...
    //	test1...
    //	lock.tryLock();
    //	System.out.println("进入test2");
    //	// 解锁
    //	lock.unlock();
    
    	// open2
    //	进入test1方法...
    //	test1...
    //	进入test2,先做其他事情
    //	test1...
    //	test1...
    //	test1...
    //	test1...
    //	test1...
    //	boolean isLocked = lock.tryLock();
    //	if (isLocked) {
    //	    System.out.println("进入test2");
    //	    // 解锁
    //	    lock.unlock();
    //	} else {
    //	    System.out.println("进入test2,先做其他事情");
    //	}
    
    	// 添加超时时间
    	boolean isLocked;
    	try {
    	    isLocked = lock.tryLock(1, TimeUnit.SECONDS);
    	    if (isLocked) {
    		System.out.println("进入test2");
    		// 解锁
    		lock.unlock();
    	    } else {
    		System.out.println("进入test2,先做其他事情");
    	    }
    	} catch (InterruptedException e) {
    	    e.printStackTrace();
    	}
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123

    4、公平锁与非公平锁的区别

    在这里插入图片描述

    可以设置公平锁和非公平锁【默认是非公平】非公平锁:
    抢夺式,谁抢到就谁执行【可以先直接抢,后排队】
    公平锁:每个线程的获取资源的几率是一样的【直接排队】

    /**
     * @author Lantzrung
     * @date 2022年8月6日
     * @Description
     */
    package com.day0806;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    // 手机生产类
    public class PhoneProducer {
    
        public static void main(String[] args) {
    	// 提供生产类的对象
    	PhoneProducer producer = new PhoneProducer();
    	// run任务类
    	Runnable task = new Runnable() {
    
    	    @Override
    	    public void run() {
    		// 循环生产手机
    		while (producer.num > 0) {
    		    producer.produceint();
    		    // 延迟
    		    try {
    			Thread.sleep(50);
    		    } catch (InterruptedException e) {
    			e.printStackTrace();
    		    }
    		}
    	    }
    	};
    	// 创建多个工人【线程】
    	Thread t1 = new Thread(task, "翠花");
    	Thread t2 = new Thread(task, "如花");
    	Thread t3 = new Thread(task, "小平");
    	// 开始生产
    	t1.start();
    	t2.start();
    	t3.start();
        }
    
        int num = 15;
    
        final Lock lock = new ReentrantLock(true);
    
        // 公平锁的源码 默认的就是非公平的
    //    public ReentrantLock() {
    //        sync = new NonfairSync();
    //    }
        
        // 然后下面还有一个源码 true设置为公平锁 false设置不公平锁
    //    public ReentrantLock(boolean fair) {
    //        sync = fair ? new FairSync() : new NonfairSync();
    //    }
        
    
        // 可重入锁
        public void produceint() {
    	// 上锁
    	lock.lock();
    	if (num >= 1) {
    	    //
    	    String name = Thread.currentThread().getName();
    	    //
    	    System.out.printf("%s生产了No.xs%d的手机!\n", name, num);
    	    //
    	    num--;
    	}
    	lock.unlock();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    3※、什么是死锁?

    ※–什么是死锁 ?(笔试题)

    两个或多个线程, 相互之间互持对方想获取的资源, 在没释放自身资源时之前, 又去试图获取其它线程持有的资源,而造成多个线程同时阻塞,
    无法解除。

    比如: A 线程持有 “1” 这个资源, 在没有释放 “1” 时, 又试图获取 “2”。 B 线程持有 “2” 这个资源, 在没有释放
    “2” 时, 又试图获取 “1”。

    这样就形成死锁。
    为了尽量避免死锁的发生, 在持有一个资源的同时, 少点去获取其它资源。
    在这里插入图片描述
    在这里插入图片描述

    /**
     * @author Lantzrung
     * @date 2022年8月7日
     * @Description
     */
    package com.day0806;
    
    public class PersonTask implements Runnable {
    
        public static void main(String[] args) {
    	PersonTask task = new PersonTask();
    	// 创建线程对象
    	Thread A = new Thread(task, "Aperson");
    	Thread B = new Thread(task, "Bperson");
    	// 启动线程
    	A.start();
    	B.start();
    //	[Aperson]尝试进入[A]密室.........
    //	[Aperson]尝试进入[A]密室!!!
    //	[Aperson]尝试进入[B]密室.........
    //	[Aperson]尝试进入[B]密室!!!
    //	[Bperson]尝试进入[B]密室.........
    //	[Bperson]尝试进入[B]密室!!!
    //	[Bperson]尝试进入[A]密室.........
    //	[Bperson]尝试进入[A]密室!!!
        }
    
        @Override
        public void run() {
    	// 1、判断是Aperson、Bperson
    	String name = Thread.currentThread().getName();
    	// 2、判断
    	if (name.equals("Aperson")) { // Aperson
    	    // A走的路径
    	    runWay(new String[] { "A", "B" });
    	} else { // Bperson
    	    // B走的路径
    	    runWay(new String[] { "B", "A" });
    	}
        }
    
        // 路线
        public void runWay(String[] keys) { // 入参锁对象 、密室{A,B} {B,A}
    	// 1、获取名称
    	String name = Thread.currentThread().getName();
    	System.out.printf("[%s]尝试进入[%s]密室.........\n", name, keys[0]);
    	// 先进入第一个密室
    	synchronized (keys[0]) {
    	    System.out.printf("[%s]尝试进入[%s]密室!!!\n", name, keys[0]);
    	    // 尝试进入第二个密室
    	    System.out.printf("[%s]尝试进入[%s]密室.........\n", name, keys[1]);
    	    // 进入第二个密室
    	    synchronized (keys[1]) {
    		// 尝试进入B密室
    		System.out.printf("[%s]尝试进入[%s]密室!!!\n", name, keys[1]);
    	    }
    	}
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    4※、线程间的通信(生产者和消费者模式)

    在这里插入图片描述

    –API: wait();导致当前线程等待; notify();唤醒在此监视器对象的单个线程 notifyAll();唤醒在此监视器对象的所有线程
    –使用wait和notify时需要同步锁修饰,同步修饰的对象锁要一致
    –//强调:调用wait和notify方法的对象是当前的对象锁【对象锁和调用方法的对象是一样的】;明确调用wait和notify的对象一致,能够确保通信操作是对应的线程

    注意:
    在这里插入图片描述
    在这里插入图片描述

    /**
     * @author Lantzrung
     * @date 2022年8月7日
     * @Description
     */
    package com.day0806;
    
    public class PhoneBuffer {
        // 手机经销商
        public static void main(String[] args) {
    	// 1、创建生产者和消费者
    	PhoneBuffer buffer = new PhoneBuffer();
    	// 1、生产者
    	ProducerThread pro = new ProducerThread();
    	pro.setBuffer(buffer);
    	pro.setName("生产者");
    	// 2、消费者
    	ConsumerThread con = new ConsumerThread();
    	con.setBuffer(buffer);
    	con.setName("消费者");
    	// 3、启动
    	pro.start();
    	con.start();
    
    	// OPEN1:
    	// 不在doNotify和dowait加上同步代码块是会出现报错的
    //	Exception in thread "消费者" Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    //	at java.lang.Object.wait(Native Method)
    //	at java.lang.Object.wait(Object.java:502)
    //	at com.day0806.PhoneBuffer.dowait(PhoneBuffer.java:45)
    //	at com.day0806.ProducerThread.run(PhoneBuffer.java:79)
    //java.lang.NullPointerException
    //	at com.day0806.ConsumerThread.run(PhoneBuffer.java:103)
    
        }
    
        // 缓存的手机
        int num = 0;
        // 定义一个标志位,判断是否为空
    //    boolean isEmpty = false;// 默认为空
        boolean isEmpty = true;// 默认为空
    
        // OPEN2
        // 唤醒同一监视器下(同步锁)的线程 
        // 通知方法 [同步修饰] 通知在该对象锁监视下的等待的线程根据同步锁唤醒的唤醒 等待线程【this】
        public synchronized void doNotify() {
    	this.notify();
        }
    
        // 等待方法 [同步修饰] [对象锁]
        public synchronized void dowait() {
    	try {
    	    this.wait();
    	} catch (InterruptedException e) {
    	    e.printStackTrace();
    	}
        }
        // OPEN2
    //    // 通知方法
    //    public void doNotify() {
    //	this.notify();
    //    }
    //
    //    // 等待方法
    //    public void dowait() {
    //    try {
    //    this.wait();
    //    } catch (InterruptedException e) {
    //    e.printStackTrace();
    //    }
    //  }
    }
    
    // 生产者线程
    class ProducerThread extends Thread {
        // 提供缓冲区的引用
        PhoneBuffer buffer;
        // 提供getset方法
    
        public PhoneBuffer getBuffer() {
    	return buffer;
        }
    
        public void setBuffer(PhoneBuffer buffer) {
    	this.buffer = buffer;
        }
    
        @Override
        public void run() {
    	while (true) {
    	    // 1、判断缓冲区是否为空
    	    if (buffer.isEmpty) {
    		// 空--则生产
    		buffer.num = (int) (Math.random() * 100 + 1);
    		System.out.println(this.getName() + "生产了:" + buffer.num + "台手机");
    		// 生产完,标志位【不为空】
    		buffer.isEmpty = false;
    		// 通知消费者进行消费
    		buffer.doNotify();
    	    } else {
    		// 不空,则等待
    		buffer.dowait();
    	    }
    	}
        }
    }
    
    // 消费者线程
    class ConsumerThread extends Thread {
        // 提供缓冲区的引用
        PhoneBuffer buffer;
        // 提供getset方法
    
        public PhoneBuffer getBuffer() {
    	return buffer;
        }
    
        public void setBuffer(PhoneBuffer buffer) {
    	this.buffer = buffer;
        }
    
        @Override
        public void run() {
    	while (true) {
    	    // 1、判断缓冲区是否为空
    	    if (buffer.isEmpty) {
    		// --空 则等待 【监视器--同步锁】
    		buffer.dowait();
    	    } else {
    		// 不空,则消费
    		System.out.println(this.getName() + "消费了:" + buffer.num + "台手机");
    		// 生产完,标志位【不为空】
    		buffer.isEmpty = true;
    		// 通知消费者进行消费
    		buffer.doNotify();
    	    }
    	}
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    要确保对象锁是一致的,否则不能唤醒

    在这里插入图片描述

  • 相关阅读:
    Zookeeper集群 + Kafka集群
    微服务 - Consul集群化 · 服务注册 · 健康检测 · 服务发现 · 负载均衡
    【Java】循环语句for、while、do-while
    高德地图实现gps轨迹坐标定位代码
    Antd pro中ProFormSelect使用initialValues
    kaldi安装流程
    Qt中QPropertyAnimation动画效果展示
    网站为什么要进行内容监控审核?国科云谈网站内容监控的必要性
    黑客(网络安全)技术自学30天
    技术内幕 | StarRocks Pipeline 执行框架(下)
  • 原文地址:https://blog.csdn.net/Lantzrung/article/details/126186491