并发编程-两个线程交替操作

这篇博客详细介绍了如何使用Java的多线程技术实现两个及三个线程交替打印1到100的数字。分别展示了使用`synchronized`关键字、`wait/notify`、`ReentrantLock`和`AtomicInteger`的方法,以及如何扩展到三个线程的情况,强调了条件变量在精确唤醒线程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两个线程按顺序交替输出1-100

继承Thread类,实现Runnable接口均可

方法一:使用synchronized关键字

public class PrintNumber extends Thread {
    private static int cnt = 0;
    private int id;  // 线程编号
    public PrintNumber(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (cnt <= 100) {
            if (cnt%2 == id) {
                synchronized (PrintNumber.class) {
                    cnt++;
                    System.out.println("thread_" + id + " num:" + cnt);
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread thread0 = new PrintNumber(0);
        Thread thread1 = new PrintNumber(1);
        thread0.start();
        thread1.start();
    }
}

方法二:使用synchronized关键字,wait和notify

public class PrintNumber extends Thread {
    private static int cnt = 0;
    private int id;  // 线程编号
    public PrintNumber(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (cnt <= 100) {
            synchronized (PrintNumber.class) {
                cnt++;
                System.out.println("thread_" + id + " num:" + cnt);
                PrintNumber.class.notify();
                try {
                    PrintNumber.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
   public static void main(String[] args) {
        Thread thread0 = new PrintNumber(0);
        Thread thread1 = new PrintNumber(1);
        thread0.start();
        thread1.start();
    }
}
public class Test {

    public static void main(String[] args){
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }

}

class Number implements Runnable{
    private int number = 1;

    @Override
    public void run(){
        while(number <= 100){
            synchronized(this){
                System.out.println(number);
                number++;
                notify();
                try{
                    if(number <= 100){
                        wait();
                    }
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

方法三:使用ReentrantLock

把synchronized换成lock,然后把wait和notify换成Condition的signal和await

public class PrintNumber extends Thread {
    private static Lock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    private int id;
    private static int cnt = 0;
    public PrintNumber(int id) {
        this.id = id;
    }

    private static void print(int id) {

    }

    @Override
    public void run() {
        while (cnt <= 100) {
            lock.lock();
            System.out.println("thread_" + id + " num:" + cnt);
            cnt++;
            condition.signal();
            try {
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        Thread thread0 = new PrintNumber(0);
        Thread thread1 = new PrintNumber(1);
        thread0.start();
        thread1.start();
    }
}

方法四:不使用锁,利用volatile实现

//两个线程,一个打印奇数,一个打印偶数
public class OneToHundred{
   static volatile int flag = 0;
   public static void main(String[] args){
      new Thread(new Task1(),"A").start();
      new Thread(new Task2(),"B").start();
   }
}

class Task1 implements Runnable{
   @Override
   public void run(){
     int i = -2;
     while(i<=99){
       if(OneToHundred.flag == 0){
          i+=2;
          System.out.println("a:" + i);
          OneToHundred.flag = 1;
       }
     }
   }
}

class Task2 implements Runnable{
   @Override
   public void run(){
     int i = -1;
     while(i<=98){
       if(OneToHundred.flag == 1){
          i+=2;
          System.out.println("b:" + i);
          OneToHundred.flag = 0;
       }
     }
   }
}

方法五:使用AtomicInteger

public class PrintNumber extends Thread {
    private static AtomicInteger cnt = new AtomicInteger();
    private int id;
    public PrintNumber(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (cnt.get() <= 100) {
            if (cnt.get()%2 == id) {
                System.out.println("thread_" + id + " num:" + cnt.get());
                cnt.incrementAndGet();
            }
        }
    }

    public static void main(String[] args) {
        Thread thread0 = new PrintNumber(0);
        Thread thread1 = new PrintNumber(1);
        thread0.start();
        thread1.start();
    }
}

扩展问题

  1. 如果是三个线程交替输出呢?
    解析:三个线程的解法可以使用while (cnt%3 == id)的方式实现忙等,但简单的唤醒+等待的方式必然不适用了, 没有判断的synchronized必然实现不了,java Object的notify和wait方法只能唤醒全部线程,然后另外两个线程输出前都需要额外判断下是否轮到自己输出了。这时候lock中condition的优势就体现出来了,它可以通过设置不同的condition来实现不同线程的精确唤醒。
public class Test {
    volatile int i = 1;

    public static void main(String[] args) throws Exception {
        Test obj = new Test();


        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (obj.i <= 100) {
                    // 上锁当前对象
                    synchronized (this) {

                        // 唤醒另一个线程
                        notifyAll();
                        if (obj.i == 101) {
                            return;
                        }

                        int i = new Integer(Thread.currentThread().getName());
                        if (obj.i % 3 == i) {
                            System.out.println("Thread " + Thread.currentThread().getName() + " " + obj.i++);
                        }
                        if(obj.i % 3==1){
                            System.out.println("==========");
                        }
                        try {
                            if (obj.i == 101) {
                                notifyAll();
                                return;
                            } else {
                                // 释放掉锁
                                wait();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };

        // 启动多个线程(想创建几个就创建几个)
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);

        t1.setName("1");
        t2.setName("2");
        t3.setName("0");
        t1.start();
        t2.start();
        t3.start();
    }
}
    public static void main(String[] args){
        Thread thread0 = new PrintNumber(0);
        Thread thread1 = new PrintNumber(1);
        Thread thread2 = new PrintNumber(2);
        thread0.start();
        thread1.start();
        thread2.start();
    }

class PrintNumber extends Thread{
    private static int cnt = 0;
    private int id;  // 线程编号
    public PrintNumber(int id) {
        this.id = id;
    }

    @Override
    public void run() {
        while (cnt < 100) {
            if (cnt % 3 == id) {
                synchronized (PrintNumber.class) {
                    cnt++;
                    System.out.println("thread_" + id + " num:" + cnt);
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值