代码可以直接拿去运行的哦!
测试主程序:
/**
* 线程轮询的五种方法
* @author chenbin78
* @version 1.0
* @create_date 2021/4/19 10:03
*/
public class ThreadPolling {
public static void main(String[] args) {
//SynchronizedTest synchronizedTest = new SynchronizedTest();
//SynchronizedBlock synchronizedBlock = new SynchronizedBlock();
//ReentrantLockCondition reentrantLockCondition = new ReentrantLockCondition();
//UnsafeCasTest unsafeCasTest = new UnsafeCasTest();
AtomicIntegerTest atomicIntegerTest = new AtomicIntegerTest();
//put线程
new Thread("put") {
@Override
public void run() {
atomicIntegerTest.put();
}
}.start();
//get线程
new Thread("get") {
@Override
public void run() {
atomicIntegerTest.get();
}
}.start();
}
}
方法一: 使用synchronized修饰函数:
/**
* 使用synchronized实现线程的轮询
* @author chenbin78
* @version 1.0
* @create_date 2021/4/19 10:06
*/
public class SynchronizedTest {
Map<Integer, Integer> map = new HashMap<>();
private int count = 1;
synchronized void put() {
for (int i = 0; i < 10; i++) {
map.put(count, count);
System.out.println(Thread.currentThread().getName() + " " + count);
count ++ ;
//唤醒get线程
this.notify(); //等待队列中只有一个线程,所以不使用notfiyAll()
try {
//等待get线程取值之后执行
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
synchronized void get() {
for (int i = 0; i < 10; i++) {
Integer integer = map.get(count - 1);
System.out.println(Thread.currentThread().getName() + "取值为:" + integer);
//唤醒put线程
this.notify(); //等待队列中只有一个线程,所以不使用notfiyAll()
try {
//等待put线程赋值之后执行
//最多等待1s, 等待1s后没被唤醒则自己醒过来
//因为最后一次循环时, 当前方法让出CPU后, 再也不会被唤醒了
this.wait(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
方法二: 使用synchronized代码块:
/**
* 使用synchronized代码块
* @author chenbin78
* @version 1.0
* @create_date 2021/4/19 10:26
*/
public class SynchronizedBlock {
private Map<Integer, Integer> map = new HashMap<>();
private Integer count = 1;
public void put() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
map.put(count, count);
System.out.println(Thread.currentThread().getName() + " put:" + count);
count ++ ;
this.notify();
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
}
public void get() {
synchronized (this) {
for (int i = 0; i < 10; i++) {
Integer integer = map.get(count - 1);
System.out.println(Thread.currentThread().getName() + " get:" + integer);
this.notify();
try {
this.wait(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
}
方法三: 使用jdk自带 ReentrantLock锁 + Condition(精准唤醒); 因为 synchronized 能实现的功能ReentrantLock也能实现:
/**
* 使用ReentrantLock+Condition来实现
* @author chenbin78
* @version 1.0
* @create_date 2021/4/19 10:35
*/
public class ReentrantLockCondition {
private Map<Integer, Integer> map = new HashMap<>();
private Integer count = 1;
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void put() {
for (int i = 0; i < 10; i++) {
try {
//加锁
lock.lock();
map.put(count, count);
System.out.println(Thread.currentThread().getName() + " put:" + count);
count ++ ;
condition.signal();
try {
//让出锁, 但是state应该不变, state应该由lock控制, 并不是condition来控制
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
} finally {
//释放锁
lock.unlock();
}
}
}
public void get() {
for (int i = 0; i < 10; i++) {
try {
lock.lock();
Integer integer = map.get(count - 1);
System.out.println(Thread.currentThread().getName() + " get:" + integer);
condition.signal();
try {
condition.await(1000, TimeUnit.MILLISECONDS);
} catch (Exception e) {
e.printStackTrace();
}
} finally {
lock.unlock();
}
}
}
}
方法四: 使用Unsafe(安全类)类的CAS操作, 不能操作时便自旋; 不涉及线程的阻塞与唤醒, 更高效:
/**
* @author chenbin78
* @version 1.0
* @create_date 2021/4/19 10:46
*/
public class UnsafeCasTest {
private Map<Integer, Integer> map = new HashMap<>();
private Integer count = 1;
//使用volatile保证flag在两个线程中的可见性
volatile int flag = 0;
private static Unsafe unsafe;
private static Long flagOffset;
static {
try {
unsafe = getUnsafeInstance();
//获取flag的偏移量, 为CAS操作做准备
//getDeclaredField()与getField
flagOffset = unsafe.objectFieldOffset(UnsafeCasTest.class.getDeclaredField("flag"));
} catch (Exception e) {
e.printStackTrace();
}
}
//获取unsafe实例
public static Unsafe getUnsafeInstance() throws Exception {
// 通过反射获取rt.jar下的Unsafe类
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
// return (Unsafe) theUnsafeInstance.get(null);是等价的
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
}
public void put() {
for (int i = 0; i < 10; i++) {
for (;;) {
if (flag == 0) {
break;
}
}
map.put(count, count);
System.out.println(Thread.currentThread().getName() + " put:" + count);
count ++ ;
int tmp = flag;
//使用CAS赋值
unsafe.compareAndSwapInt(this, flagOffset, tmp, 1);
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
public void get() {
for (int i = 0; i < 10; i++) {
for (;;) {
if (flag == 1) {
break;
}
}
Integer integer = map.get(count - 1);
System.out.println(Thread.currentThread().getName() + " get:" + integer);
int tmp = flag;
unsafe.compareAndSwapInt(this, flagOffset, tmp, 0);
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
}
方法五: 使用AtomicInteger(原子操作); 不能操作时便自旋:
/**
* @author chenbin78
* @version 1.0
* @create_date 2021/4/19 11:12
*/
public class AtomicIntegerTest {
private Map<Integer, Integer> map = new HashMap<>();
private int count = 1;
//0表示线程0可以执行, 1表示线程1可以执行
AtomicInteger atomicInteger = new AtomicInteger(0);
public void put() {
for (int i = 0; i < 10; i++) {
//自旋
for (;;) {
if ((atomicInteger.intValue() & 1) == 0) {
break;
}
}
map.put(count, count);
System.out.println(Thread.currentThread().getName() + "put:" + count);
count ++ ;
atomicInteger.compareAndSet(atomicInteger.intValue(), 1);
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
public void get() {
for (int i = 0; i < 10; i++) {
//自旋
for (;;) {
if ((atomicInteger.intValue() & 1) == 1) {
break;
}
}
Integer integer = map.get(count - 1);
System.out.println(Thread.currentThread().getName() + " get:" + integer);
atomicInteger.compareAndSet(atomicInteger.intValue(), 0);
}
System.out.println(Thread.currentThread().getName() + "执行完毕!");
}
}