用synchronized关键字实现
public class TestMain {
//定义一个int变量
private static volatile int number = 0;
//定义一个对象锁
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
//偶数线程
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
//判断数值是否小于100,小于则进入同步块做判断输出和自增
while (number < 100) {
synchronized (lock) {
//等价于number%2==0,用位运算效率更高
if ((number & 1) == 0) {
System.out.println(Thread.currentThread().getName() + ":" + number++);
}
}
}
}
}, "偶数");
//奇数线程
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
//判断数值是否小于100,小于则进入同步块做判断输出和自增
while (number < 100) {
synchronized (lock) {
//等价于number%2==1,用位运算效率更高
if ((number & 1) == 1) {
System.out.println(Thread.currentThread().getName() + ":" + number++);
}
}
}
}
}, "奇数");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
}
}
运行结果如下:
可以发现两次运行的时间差大概都有2倍了,这是因为用synchronized关键字来实现,虽然结果是可以达到预期的,但是在多线程运行中,往往可能一个线程能多次得到运行机会,这样就会导致时间的浪费,所以我们虽然看到的是两个线程交替打印奇偶数,但很大的可能是其中一个线程都做了好几次同步块的逻辑,另一个线程才抢到运行的机会,所以效率快慢完全看运气。
使用wait/notify来实现
public class TestMain {
//定义一个int变量
private static volatile int number = 0;
//定义一个对象锁
private static final Object lock = new Object();
static class NumberThread implements Runnable {
@Override
public void run() {
//小于等于100则进入同步块
while (number <= 100) {
synchronized (lock) {
//输出当前值后加一
System.out.println(Thread.currentThread().getName() + ":" + number++);
//唤醒等待中的线程
lock.notify();
//这个判断很关键,要是不写,结果输出虽然是一样的,但是程序运行不会结束,因为有线程会陷入无限的等待,而没有其他线程可以来唤醒它
if (number <= 100) {
try {
//让出CPU资源,释放锁,让另一个线程运行,同时等待被另一个线程唤醒
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
NumberThread numberThread = new NumberThread();
Thread thread1 = new Thread(numberThread, "偶数");
Thread thread2 = new Thread(numberThread, "奇数");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("总耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");
}
}
运行结果如下:
一个线程输出完值后,如果还没有达到100,就会唤醒与之配合的另一个线程同时自己让出锁资源进入等待,等待唤醒,这样子就算真正的实现交替运行。
总结
实现需求方法有很多种,试着选择自己能力范围内的最优解。