这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战
前言
经过了前面几期的学习(划水),对于多线程并发编程也算有点概念了,当然了对于实战虽然有点距离,但是应付下面试题,是可以的了。至少从线程的创建→关闭都能答出来哈哈哈哈哈哈~
言归正传,多线程可不止口头问的,如果有笔试可能还需要手撕代码,这就需要熟练掌握,并拿捏好其中的加分点了。
用两个线程交替打印0-100的奇偶数
一般我们在笔试的时候 ,最后几道可能是手撕算法题。或者直接白纸撸代码,题目可能不会很复杂,毕竟直接考验的就是你的代码功底。当然了,碰到相同相似题目的概率也是极大的~
方法一 :利用synchronized通信实现线程的交替
- 定义两个线程,同步机制获取锁
- 判断奇偶数,用位运算(取最后一位,与1 位运算,如果为0则为偶数,为1则为奇数),取代 count % 2 == 0(重点加分!!!!)
private static Integer count = 0;
private static final Object lock = new Object() ;
public static void main(String[] args) throws InterruptedException {
/**
* 利用synchronized通信实现线程的交替
*/
new Thread(() -> {
while (count<=100){
synchronized (lock){
if ((count & 1) == 0){
System.out.println(Thread.currentThread().getName()+"打印出"+(count++));
}
}
}
},"偶数").start();
new Thread(() -> {
while (count<100){
synchronized (lock){
if ((count & 1) == 1){
System.out.println(Thread.currentThread().getName()+"打印出"+(count++));
}
}
}
},"奇数").start();
}
方法二:利用 wait() 和 notify() 方法,实现交替
- 定义一个类实现Runnable接口,重写run方法
- 获取锁之后,直接打印输出,不需要校验
- 唤醒该锁资源,并释放当前线程资源
- main方法定义两个线程,因为首次为0,所以第一个线程为偶线程,以防万一,可以启动第一个线程后,主线程睡眠等待偶线程启动完成
private static Integer count = 0;
private static final Object lock = new Object() ;
static class WaitNotify implements Runnable{
@Override
public void run() {
while (count<=100){
synchronized (lock){
System.out.println(Thread.currentThread().getName()+"打印出"+(count++));
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new WaitNotify(),"偶数");
thread1.start();
Thread.sleep(10);
Thread thread2 = new Thread(new WaitNotify(),"奇数");
thread2.start();
}
小总结
- 对于两个方法来说,方法二肯定是优于方法一的;(wait()/notify() > synchronized)
- synchronized 通信,有加分点,用 位运算(count & 1) 取代 取余(count % 2) ,但是也有不足之处;
资源抢夺的时候,两个线程不一定交替,有可能偶线程执行完后,往后的多次依然被偶线程抢夺到资源去执行,虽然其中有校验,对结果不影响,但是造成了多次的无用执行。 - 用wait() 和 notify() 方法,不需要过多关注哪一个线程为奇偶线程,只需要 先执行,即为 偶线程;
一个线程结束运行释放并唤醒其他线程,即可满足当前需求,且无过多无用操作。