线程有序输出的四种写法
问题:三个线程有序输出abc
思路:各个线程有序的释放资源,得不到资源的线程陷入阻塞,最后使得线程之间有序协作啦!
法子一:只将输出方法 设为同步方法,别的,什么都不做,while循环,线程们去不停的抢吧,最笨的方法QAQ
输出方法:
public synchronized void print(String name) {
// System.out.println("线程 "+name+" 进来了");
switch (name) {
case "a":
if (a > 0) {
a--;
System.out.println("A");
b++;
//一轮输出结束
end--;
}
break;
case "b":
if (b > 0) {
b--;
// System.out.println("要输出b 的是 "+name);
System.out.println("B");
c++;
}
break;
case "c":
if (c > 0) {
c--;
// System.out.println("要输出c 的是 "+name);
System.out.println("C");
a++;
}
break;
}
// System.out.println("线程 "+name+" 走了");
}
内部线程类:
class MyThread extends Thread {
public MyThread(String tName) {
super(tName);
}
@Override
public void run() {
while (end > 0) {
print(getName());
}
long endtime = System.currentTimeMillis();
System.out.println("线程 " + getName() + " 运行了 " + (endtime - start_time) + "ms");
}
}
测试类:
public class Ttest {
int a = 1; //信号量a
int b = 0; //信号量b
int c = 0; //信号量c
int end = 100_000; //输出次数
long start_time; //开始时间
public Ttest() {
start_time = System.currentTimeMillis();
MyThread a = new MyThread("a");
MyThread b = new MyThread("b");
MyThread c = new MyThread("c");
a.start();
b.start();
c.start();
}
public static void main(String[] args) {
new Ttest();
}
10万轮儿的运行时间:
方法二:采用wait()和notifyAll()方法 整体思想和法一大体样
输出方法:
public void print(String name) throws InterruptedException {
// System.out.println(name+" 线程进入");
synchronized (lock) {
switch (name) {
case "a":
while (a < 1) {
//当资源不足的时候 释放锁陷入阻塞
// System.out.println("线程 "+name+"资源不足陷入阻塞");
lock.wait();
// System.out.println("线程 "+name+"被唤醒");
}
//资源足够 开始输出
//消耗资源
a--;
System.out.println("线程" + name + "输出 ==a");
//释放b资源
b++;
break;
case "b":
while (b < 1) {
//当资源不足的时候 释放锁陷入阻塞
// System.out.println("线程 "+name+"资源不足陷入阻塞");
lock.wait();
// System.out.println("线程 "+name+"被唤醒");
}
//资源足够 开始输出
//消耗资源
b--;
System.out.println("线程" + name + "输出 ==b");
//释放c资源
c++;
break;
case "c":
while (c < 1) {
//当资源不足的时候 释放锁陷入阻塞
// System.out.println("线程 "+name+"资源不足陷入阻塞");
lock.wait();
// System.out.println("线程 "+name+"被唤醒");
}
//资源足够 开始输出
//消耗资源
c--;
System.out.println("线程" + name + "输出 ==c");
//释放a资源
a++;
break;
}
//唤醒等待线程
lock.notifyAll();
}
}
10万次的运行时间:
比方法一快了25%左右
方法三:使用Semaphore信号量
输出方法:
public void print(String name) throws InterruptedException {
switch (name){
case "a":
a.acquire();//请求操作
System.out.println("线程:"+name+"输出 a");
b.release();//释放资源操作
break;
case "b":
b.acquire();
System.out.println("线程:"+name+"输出 b");
c.release();
break;
case "c":
c.acquire();
System.out.println("线程:"+name+"输出 c");
a.release();
break;
}
}
public class TTest3 {
//abc信号量
private Semaphore a, b, c;
private long startTime;
public TTest3(){
startTime = System.currentTimeMillis();
a = new Semaphore(1);
b = new Semaphore(0);
c = new Semaphore(0);
Mt3 ta = new Mt3("a");
Mt3 tb = new Mt3("b");
Mt3 tc = new Mt3("c");
tb.start();
tc.start();
ta.start();
}
更快一些了噢
方法四: 自己封装 wait notify 成 pv操作 (操作系统噢)
public class ISemaphore {
private int semaphore;//信号量
public ISemaphore(int semaphore) {
this.semaphore = semaphore;
}
public synchronized void p() throws InterruptedException {
//若信号量小于等0 持有该对象的线程陷入阻塞
while (semaphore <= 0) {
this.wait();
}
//信号量减一
semaphore--;
}
public synchronized void v() {
//释放资源
semaphore++;
this.notifyAll();
}
}
输出方法:
public void print(String name) throws InterruptedException {
switch (name){
case "a":
//请求a资源
a.p();
System.out.println("线程"+name+"输出了 ==a");
//释放b资源
b.v();break;
case "b":
//请求b资源
b.p();
System.out.println("线程"+name+"输出了 ==b");
//释放c资源
c.v();break;
case "c":
//请求c资源
c.p();
System.out.println("线程"+name+"输出了 ==c");
//释放a资源
a.v();break;
}
}
测试类:
private ISemaphore a, b, c;
private long startTime;
private int end = 100_000;
public TestSemaphore(){
a = new ISemaphore(1);
b = new ISemaphore(0);
c = new ISemaphore(0);
startTime = System.currentTimeMillis();
new myT("b",end).start();
new myT("c",end).start();
new myT("a",end).start();
}
public static void main(String[] args) {
new TestSemaphore();
}
10万次:
好像又快些了噢