原文:http://edisonxu.org/2017/03/02/java-thread-communication.html
题目: 编写两个线程,一个线程打印1~25,另一个线程打印字母A~Z,打印顺序为12A34B56C……5152Z,要求使用线程间的通信。
通用代码
package ThreadLearnCommunicate;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by Edison Xu on 2017/3/2.
*/
public enum Helper {
instance;
private static final ExecutorService tPool = Executors.newFixedThreadPool(2);
public static String[] buildNoArr(int max) {
String[] noArr = new String[max];
for(int i=0;i<max;i++){
noArr[i] = Integer.toString(i+1);
}
return noArr;
}
public static String[] buildCharArr(int max) {
String[] charArr = new String[max];
int tmp = 65;
for(int i=0;i<max;i++){
charArr[i] = String.valueOf((char)(tmp+i));
}
return charArr;
}
public static void print(String... input){
if(input==null)
return;
for(String each:input){
System.out.print(each);
}
}
public void run(Runnable r){
tPool.submit(r);
}
public void shutdown(){
tPool.shutdown();
}
}
1.synchronized + notify + wait +flag(控制变量)
package ThreadLearnCommunicate;
public class MethordOne {
private ThreadToGo go = new ThreadToGo();
public Runnable Threadone(){
final String[] inputArr= Helper.buildCharArr(26);
return new Runnable() {
public void run() {
for(int i =0;i<inputArr.length;i++){
synchronized (go) {
while(go.value==1){
try {
go.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
Helper.print(inputArr[i]);
go.value=1;
go.notify();
}
}
}
};
}
public Runnable Threadtwo(){
final String[] inputArr= Helper.buildNoArr(52);
return new Runnable() {
public void run() {
for(int i =0;i<inputArr.length;i+=2){
synchronized (go) {
while(go.value==2){
try {
go.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
Helper.print(inputArr[i],inputArr[i+1]);
go.value=2;
go.notify();
}
}
}
};
}
public static void main(String[] args) {
MethordOne m =new MethordOne();
Helper.instance.run(m.Threadone());
Helper.instance.run(m.Threadtwo());
Helper.instance.shutdown();
}
class ThreadToGo{
int value =1;
}
}
2.使用lock和condition+flag
package ThreadLearnCommunicate;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import ThreadLearnCommunicate.MethordOne.ThreadToGo;
public class MethordTwo {
private Lock lock =new ReentrantLock(true);
private Condition condition = lock.newCondition();
private ThreadToGo go = new ThreadToGo();
public Runnable Threadone(){
final String[] inputArr= Helper.buildCharArr(26);
return new Runnable() {
public void run() {
for(int i =0;i<inputArr.length;i++){
lock.lock();
try {
while(go.value==1)
condition.await();
Helper.print(inputArr[i]);
go.value=1;
condition.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}finally {
lock.unlock();
}
}
}
};}
public Runnable Threadtwo(){
final String[] inputArr= Helper.buildNoArr(52);
return new Runnable() {
public void run() {
for(int i =0;i<inputArr.length;i+=2){
lock.lock();
try {
while(go.value==2)
condition.await();
Helper.print(inputArr[i],inputArr[i+1]);
go.value=2;
condition.signal();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}finally {
lock.unlock();
}
}
}
};}
public static void main(String[] args) {
MethordTwo m =new MethordTwo();
Helper.instance.run(m.Threadone());
Helper.instance.run(m.Threadtwo());
Helper.instance.shutdown();
}
class ThreadToGo{
int value =1;
}
}
3.使用 volatile关键字, volatile修饰的变量值直接存在main memory里面,子线程对该变量的读写直接写入main memory,而不是像其它变量一样在local thread里面产生一份copy。volatile能保证所修饰的变量对于多个线程可见性,即只要被修改,其它线程读到的一定是最新的值。
package ThreadLearnCommunicate;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import ThreadLearnCommunicate.MethordOne.ThreadToGo;
public class MethordThree {
private volatile ThreadToGo go = new ThreadToGo();
public Runnable Threadone() {
final String[] inputArr = Helper.buildCharArr(26);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i++) {
while(go.value==1){}
Helper.print(inputArr[i]);
go.value = 1;
}
}
};
}
public Runnable Threadtwo() {
final String[] inputArr = Helper.buildNoArr(52);
return new Runnable() {
private String[] arr = inputArr;
public void run() {
for (int i = 0; i < arr.length; i += 2) {
while(go.value==2){}
Helper.print(inputArr[i],inputArr[i+1]);
go.value = 2;
}
}
};
}
public static void main(String[] args) {
MethordThree m = new MethordThree();
Helper.instance.run(m.Threadone());
Helper.instance.run(m.Threadtwo());
Helper.instance.shutdown();
}
class ThreadToGo {
int value = 1;
}
}
4.通过AtomicInteger类实现(AtomicInteger是一个线程安全的类)
package ThreadLearnCommunicate;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import ThreadLearnCommunicate.MethordOne.ThreadToGo;
public class MethordFour {
private AtomicInteger go =new AtomicInteger(1);
public Runnable Threadone() {
final String[] inputArr = Helper.buildCharArr(26);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i++) {
while(go.get()==1){}
Helper.print(inputArr[i]);
go.set(1);
}
}
};
}
public Runnable Threadtwo() {
final String[] inputArr = Helper.buildNoArr(52);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i += 2) {
while (go.get()==2) {}
Helper.print(inputArr[i],inputArr[i+1]);
go.set(2);
}
}
};
}
public static void main(String[] args) {
MethordFour m = new MethordFour();
Helper.instance.run(m.Threadone());
Helper.instance.run(m.Threadtwo());
Helper.instance.shutdown();
}
}
5.利用CyclicBarrierAPI实现 CyclicBarrier可以实现让一组线程在全部到达Barrier时(执行await()),再一起同时执行,并且所有线程释放后,还能复用它,即为Cyclic。
package ThreadLearnCommunicate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class MethordFive {
private final CyclicBarrier barrier;
private final List<String> list;
public MethordFive(){
list = Collections.synchronizedList(new ArrayList<String>());
barrier = new CyclicBarrier(2, newBarrierAction());
// TODO Auto-generated constructor stub
}
public Runnable Threadone() {
final String[] inputArr = Helper.buildCharArr(26);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i++) {
list.add(inputArr[i]);
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}
public Runnable Threadtwo() {
final String[] inputArr = Helper.buildNoArr(52);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i += 2) {
list.add(inputArr[i]);
list.add(inputArr[i+1]);
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}
private Runnable newBarrierAction(){
return new Runnable() {
public void run() {
Collections.sort(list);
list.forEach(c->System.out.print(c));
list.clear();
}
};
}
public static void main(String[] args) {
MethordOne m = new MethordOne();
Helper.instance.run(m.Threadone());
Helper.instance.run(m.Threadtwo());
Helper.instance.shutdown();
}
}
6.利用BlockingQueue
package ThreadLearnCommunicate;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class MethodSix{
private LinkedBlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();
public Runnable Threadone() {
final String[] inputArr = Helper.buildCharArr(26);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i++) {
blockingQueue.offer("twoGo");
while(!"oneGo".equals(blockingQueue.peek())){}
Helper.print(inputArr[i]);
blockingQueue.poll();
}
}
};
}
public Runnable Threadtwo() {
final String[] inputArr = Helper.buildNoArr(52);
return new Runnable() {
public void run() {
for (int i = 0; i < inputArr.length; i++) {
while(!"twoGo".equals(blockingQueue.peek())){}
blockingQueue.poll();
Helper.print(inputArr[i],inputArr[i+1]);
blockingQueue.offer("oneGo");
}
}
};
}
public static void main(String[] args) {
MethodSix m = new MethodSix();
Helper.instance.run(m.Threadone());
Helper.instance.run(m.Threadtwo());
Helper.instance.shutdown();
}
}
第二种实现,通过定义两个阻塞队列
package ThreadLearnCommunicate;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class MethodSix{
private final LinkedBlockingQueue<String> queue1 = new LinkedBlockingQueue<>();
private final LinkedBlockingQueue<String> queue2 = new LinkedBlockingQueue<>();
public Runnable newThreadThree() {
final String[] inputArr = Helper.buildNoArr(52);
return new Runnable() {
private String[] arr = inputArr;
public void run() {
for (int i = 0; i < arr.length; i=i+2) {
Helper.print(arr[i], arr[i + 1]);
try {
queue2.put("TwoToGo");
queue1.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
}
public Runnable newThreadFour() {
final String[] inputArr = Helper.buildCharArr(26);
return new Runnable() {
private String[] arr = inputArr;
public void run() {
for (int i = 0; i < arr.length; i++) {
try {
queue2.take();
Helper.print(arr[i]);
queue1.put("OneToGo");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
}
public static void main(String[] args) {
MethodSix m = new MethodSix();
Helper.instance.run(m.newThreadThree());
Helper.instance.run(m.newThreadFour());
Helper.instance.shutdown();
}
}