两个线程交替打印奇偶数

news/2024/5/17 16:53:12 标签: 多线程, 交替打印, Synchronized, ReentranLock

题目:使用两个线程交替打印1-10

依照题意:线程0打印1,线程1打印2,接着再次这样循环,一直到输出10为止。

我首先想到的是线程间的通信,首先让线程0执行,输出1,然后notify唤醒线程1,之后线程0立马wait释放锁。线程1拿到锁之后,输出2,同样,notify唤醒线程0,接着自己立马wait释放锁。

先写个示例代码:

package com.yang.testThreadPrint;

public class Main {

    //输出的最大数字
    private static final int MAX_NUM = 10;
    //自增变量
    private static volatile int i = 1;
    //临界资源
    private static final Object object = new Object();

    public static void main(String[] args) {

        Runnable r = new Runnable() {
            @Override
            public void run() {
                synchronized (object) {
                    while (i <= MAX_NUM) {
                        System.out.println(Thread.currentThread().getName() + ":" + i++);
                        try {
                            object.notify();
                            object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //防止有子线程被阻塞未被唤醒,导致主线程不退出
                    object.notify();
                }
            }
        };

        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
    }
}

输出结果:


顺便补充一些wait与notify的基础

wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行, 只有其他线程调用了notify方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还 在别人手里,别人还没释放。如果notify/notifyAll方法后面的代码还有很多,需要这些代码执行完后才会释放锁),调用wait方法的一个或多个线程就会解除wait状态,重新参与竞争对象锁,程序如果可以再次得到锁,就可以继续向下运行。

  • wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
  • wait()必须在同步块之内,且需要捕捉异常
  • 当前线程必须拥有此对象的锁,才能调用某个对象的wait()方法能让当前线程阻塞,(这种阻塞是通过提前释放synchronized锁,重新去请求锁导致的阻塞,这种请求必须有其他线程通过notify()或者notifyAll()唤醒重新竞争获得锁)
  • 调用某个对象的notify()方法能够唤醒一个正在等待这个对象锁的线程,如果有多个线程都在等待这个对象锁,则只能唤醒其中一个线程
  • 调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程,唤醒的线程获得锁的概率是随机的,取决于cpu调度

关于wait()与sleep()的区别,可以参考我的另外一篇文章sleep与wait的区别


上面是使用synchronized+wait+notify,下面使用ReentranLock+condition,本质上都是线程间通信

package com.yang.testThreadPrint;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MainByLock {

    //输出的最大数字
    private static final int MAX_NUM = 10;
    //自增变量
    private static volatile int i = 1;
    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();


    public static void main(String[] args) {

        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    while (i <= MAX_NUM) {
                        System.out.println(Thread.currentThread().getName() + ":" + i++);
                        condition.signal();
                        try {
                            condition.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        condition.signal();
                    }
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
    }
}

 


http://www.niftyadmin.cn/n/1705422.html

相关文章

设计模式初学者系列-单件模式

本系列文章目录 本文章首发在IT168技术频道&#xff0c;有修改 点击这里查看 在一个系统中&#xff0c;往往有一些服务只需要它们在整个系统中存在一个实例&#xff0c;并且在系统的任何角落都可以访问它。这样&#xff0c;单件模式出现了。比如在上一篇抽象工厂模式中&#x…

Linux:有光明没前途

作者: 孙永杰 出处:孙永杰的Sina博客 近日&#xff0c;随着欧盟就微软垄断案的调查以及微软最新Vista操作系统销售的不理想&#xff0c;Linux再度受到人们的热捧&#xff08;至少从最近媒体和业内人士的文章和评论中可见一斑&#xff09;。但笔者从一个普通用户和记者的角度认为…

初探Docker网络模式

Docker使用Linux桥接&#xff08;参考《Linux虚拟网络技术》&#xff09;&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&#xff0c;Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址&#xff0c;称为Container-IP&#xff0c;同时Docker网桥是每个容器…

exchange邮件备份软件GFI MailArchiver

使用MailArchiver保存您的邮件<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />“我昨天可能误删除了一份重要的邮件&#xff01;怎么才能恢复它&#xff1f;”“我的Outlook文件损坏了&#xff01;我的收件箱里有很多客户的订单…

【K8S】Volume类型-EmptyDir与HostPath的区别

我们知道&#xff0c;一个运行中的容器&#xff0c;默认情况下&#xff0c;对文件系统的写入&#xff0c;都是发生在其分层文件系统的可写层的&#xff0c;一旦容器运行结束&#xff0c;所有写入都会被丢弃。因此需要支持容器数据的持久化。 k8s中通过Volume来提供对容器存储的…

mysql 5.6.20 数据库中文乱码解决方法

1、打开mysql5.6安装目录下面的文件my-default.ini在[client]下面添加default-character-setutf8&#xff08;如果没有[client]自己手动添加&#xff09;。然后在[mysqld]下面添加character_set_server utf8&#xff08;如果没有[mysqld]自己手动添加&#xff09; 2、在mysql5…

2008秋-计算机软件基础-第四章习题参考答案 P131 ,习题4,5

Author: Eman Lee 计算机软件基础&#xff0c;教材 P131&#xff0c;第4题 参考答案 &#xff08;1&#xff09;查找e的过程 a b c d e f g h Low1 Mid4 High8 a b c d e f g h Low5 Mid6 High8 a b c d e f g h Low5 Mid5 High5 查找成功 &am…

Lesson 63-64 Who has the most stressful job?

1 at any time 随时 right now 立即&#xff0c;目前 at a time 每次 just now刚才 at the moment当时&#xff0c;现在 aging 老化n&#xff0c;变老v eg. Chinas population is aging at unprecedented levels.使中国人口老龄化达到了前所未有的水平. 2 commission委托nv …