synchronized方式
public class A1B2C3Synchronized {
private static Object o = new Object ();
private static volatile boolean flag = false;
public static void main(String[] args) {
char[] chars1 = "ABCDEF".toCharArray ();
char[] chars2 = "123456".toCharArray ();
new Thread (() -> {
synchronized (o) {
while(flag){}
for (int i = 0; i < chars1.length; i++) {
System.out.print (chars1[i]);
flag = true;
//唤醒等待线程,只有两个线程,所以这里唤醒的事另一个线程
o.notify ();
try {
o.wait ();
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
}
}).start ();
new Thread (() -> {
synchronized (o) {
while(!flag){}
for (int i = 0; i < chars2.length; i++) {
System.out.println (chars2[i]);
//唤醒等待线程,只有两个线程,所以这里唤醒的事另一个线程
o.notify ();
try {
o.wait ();
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
}
}).start ();
}
}
LockSupport方式
public class A1B2C3LockSupport {
private static Object o = new Object ();
private static Thread t1, t2;
private static volatile boolean flag = false;
public static void main(String[] args) {
char[] chars1 = "ABCDEF".toCharArray ();
char[] chars2 = "123456".toCharArray ();
t1 = new Thread (() -> {
while(flag){}
for (int i = 0; i < chars1.length; i++) {
LockSupport.unpark (t2);
System.out.print (chars1[i]);
flag = true;
LockSupport.park ();
}
});
t2 = new Thread (() -> {
while(!flag){}
for (int i = 0; i < chars2.length; i++) {
LockSupport.park ();
System.out.println (chars2[i]);
LockSupport.unpark (t1);
}
});
t1.start ();
t2.start ();
}
}
CAS的两种方式(1)
public class A1B2C3CAS {
private static Object o = new Object ();
private static Thread t1, t2;
private static volatile boolean flag = false;
public static void main(String[] args) {
char[] chars1 = "ABCDEF".toCharArray ();
char[] chars2 = "123456".toCharArray ();
//利用volatile自旋,也可以使用AtomicInteger
t1 = new Thread (() -> {
for (int i = 0; i < chars1.length; i++) {
while (flag) {}
System.out.print (chars1[i]);
flag = true;
}
});
t2 = new Thread (() -> {
for (int i = 0; i < chars1.length; i++) {
while (!flag) {}
System.out.println (chars2[i]);
flag = false;
}
});
t1.start ();
t2.start ();
}
}
CAS的两种方式(2)
public class A1B2C3CAS1 {
static Unsafe unsafe;
int flag = 0;
static long headOffset ;
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
unsafe = UnsafeInit ();
//偏移量,compareAndSwapObject方法的第二个参数
headOffset = unsafe.objectFieldOffset (A1B2C3CAS1.class.getDeclaredField ("flag"));
char[] chars1 = "ABCDEF".toCharArray ();
char[] chars2 = "123456".toCharArray ();
new Thread (() -> {
for (int i = 0; i < chars1.length; i++) {
//两次cas为了保证两个线程的打印顺序
while (!unsafe.compareAndSwapInt (A1B2C3CAS1.class, headOffset, 0,2)){}
System.out.print (chars1[i]);
unsafe.compareAndSwapInt (A1B2C3CAS1.class, headOffset, 2,1);
}
}).start ();
new Thread (() -> {
for (int i = 0; i < chars2.length; i++) {
while (!unsafe.compareAndSwapInt (A1B2C3CAS1.class, headOffset, 1,2)){}
System.out.println (chars2[i]);
unsafe.compareAndSwapInt (A1B2C3CAS1.class, headOffset, 2,0);
}
}).start ();
}
public static Unsafe UnsafeInit() throws NoSuchFieldException, IllegalAccessException {
//创建unsafe
Class> clazz = Unsafe.class;
Field f = clazz.getDeclaredField ("theUnsafe");
f.setAccessible (true);
return ( Unsafe ) f.get (clazz);
}
}
阻塞队列方式
public class A1B2C3BlockingQueue {
/**
* 很多队列都能实现,这里使用数组阻塞队列举例
*/
static BlockingQueue q1 = new ArrayBlockingQueue (1);
static BlockingQueue q2 = new ArrayBlockingQueue (1);
public static void main(String[] args) {
char[] chars1 = "ABCDEF".toCharArray ();
char[] chars2 = "123456".toCharArray ();
new Thread (() -> {
for (int i = 0; i < chars1.length; i++) {
try {
System.out.print (q1.take ());
q2.put (chars2[i]);
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
}).start ();
new Thread (() -> {
for (int i = 0; i < chars2.length; i++) {
try {
q1.put (chars1[i]);
System.out.println (q2.take ());
} catch (InterruptedException e) {
e.printStackTrace ();
}
}
}).start ();
}
}
等待队列方式
/**
* 个人认为等待队列稍微难理解一点
*/
public class A1B2C3Lock {
static ReentrantLock reentrantLock;
static volatile boolean flag = true;
public static void main(String[] args) {
char[] chars1 = "ABCDEF".toCharArray ();
char[] chars2 = "123456".toCharArray ();
reentrantLock = new ReentrantLock ();
Condition condition = reentrantLock.newCondition ();
new Thread (() -> {
//利用flag保证线程1在线程2之前执行
while(!flag){}
flag = false;
try {
//线程1先获取锁
reentrantLock.lock ();
for (int i = 0; i < chars1.length; i++) {
//将等待队列线程同步到CLH队列
condition.signal ();
System.out.print (chars1[i]);
//将线程1放到等待队列,并唤醒CLH队列head的下一个node代表的线程唤醒
condition.await ();
}
} catch (InterruptedException e) {
e.printStackTrace ();
} finally {
/**为什么加这一段代码,t2是在打印F6的6以后,通过await方法将t2存放到等待队列中,并
唤醒t1线程,所以此时CLH队列中只有t1,而线程被唤醒只能是在CLH队列中,这段代码就是将t2
线程从等待队列中转移到CLH队列,通过unlock将t2唤醒*/
condition.signal ();
reentrantLock.unlock ();
}
}, "t1").start ();
new Thread (() -> {
while(flag){}
try {
reentrantLock.lock ();
for (int i = 0; i < chars2.length; i++) {
condition.signal ();
System.out.println (chars2[i]);
condition.await ();
}
} catch (InterruptedException e) {
e.printStackTrace ();
} finally {
reentrantLock.unlock ();
}
}, "t2").start ();
}
}