Hey Thread
Sow nothing, reap nothing. –春不播,秋不收.
最近闲暇无事的时候,逛了逛论坛,发现有的同学对于多线程有着一定的盲区,并且提出了几个多线程的问题,我就在私下里写了两个例子简单说明下多线程的应用,就是多线程有序打印n遍abc的问题.
实现方法一 : 通过java中的AtomicInteger原子性操作完成,线程无非就是原子性的问题
/**
* 使用多线程 循环打印 20 遍 ABC
*/
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
AtomicInteger runFlag = new AtomicInteger(1);
// 当前的是1
System.out.println(runFlag.get());
// 期待的是1 所以是true 然后更新为 update 4
boolean b1 = runFlag.compareAndSet(1, 4);
System.out.println(b1);
// 此时变为了 4
System.out.println(runFlag.get());
Thread a = new Thread(new PrintRunable("A", 1, 2));
Thread b = new Thread(new PrintRunable("B", 2, 3));
Thread c = new Thread(new PrintRunable("C", 3, 1));
a.start();
b.start();
c.start();
// 主线程让子线程.
a.join();
b.join();
c.join();
}
static class PrintRunable implements Runnable{
// 需要打印的字符串
private String str;
// 什么时候执行
private static AtomicInteger runFlag = new AtomicInteger(1);
// 当前的顺序
private int mySequence;
// 下一个执行
private int next;
// 构造方法 构造参数是 打印的值,当前的序号,下一个是谁
private PrintRunable(String str,int mySequence,int next){
this.mySequence = mySequence;
this.next = next;
this.str = str;
}
// 打印的次数
private static int count = 20;
@Override
public void run() {
while (true) {
if(count<0){
return;
}
// 判断 当前的 runFlag 是否和 标志是否一样 如果一样,那么就打印str
if (runFlag.get() == mySequence) {
show();
}
}
}
public void show(){
// 打印
System.out.println(str);
// 判断 下一个是否比当前的书序小 如果是的话,需要重新开始打印,又是新的开始
if(next<mySequence)
System.out.println("------>"+count--);
// 执行下一次。。将next 给mySequence 进行换值
runFlag.compareAndSet(mySequence,next);
}
}
}
方法二: 通过Lock锁,保证原子性操作.
public class ThreadTestB {
static int num = 1;
int count = 1;
// 创建 锁
private Lock lock = new ReentrantLock();
// 穿件 Condition 队列
Condition locka = lock.newCondition();
Condition lockb = lock.newCondition();
Condition lockc = lock.newCondition();
// 打印 A
public void showA() {
// 上锁
lock.lock();
try {
// 如果 不是 1 那么 等待
while (num!=1){
locka.await();
}
// num 是 1
System.out.println("A");
// 轮到 b 输出
num=2;
// 解开 b 的锁
lockb.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void showB() {
lock.lock();
try {
while (num!=2){
lockb.await();
}
System.out.println("B");
num=3;
lockc.signal();
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void showC() {
lock.lock();
try {
while (num!=3){
lockc.await();
}
System.out.println("C");
num=1;
locka.signal();
System.out.println("---》" + count);
count++;
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
ThreadTestB printABC = new ThreadTestB();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
printABC.showA();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
printABC.showB();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
printABC.showC();
}
}
}).start();
}
}
以上两种方法就简单的实现了多线程的应用. 至于 为什么第一种方法中的AutomicInteger 是原子性的,我翻了翻源码,发现了关键字volatile,由此保证了线程之间的可见性.
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//保证了 原子性,可见性
private volatile int value;
/**
* Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
}