diff --git a/.classpath b/.classpath index fb50116..45cb5c9 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,8 @@ + + diff --git a/.project b/.project index 6e26036..76d1107 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - JerryDesignPattern + JerryMultiThread diff --git a/lib/mail.jar b/lib/mail.jar new file mode 100644 index 0000000..d1a4971 Binary files /dev/null and b/lib/mail.jar differ diff --git a/src/com/jerry/mail/Encrypt.java b/src/com/jerry/mail/Encrypt.java new file mode 100644 index 0000000..dbc15aa --- /dev/null +++ b/src/com/jerry/mail/Encrypt.java @@ -0,0 +1,71 @@ +package com.jerry.mail; + +import java.security.Key; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; + +import sun.misc.BASE64Decoder; + +/** + * JAVA实现的DES加密解密算法 + * @author Jerry Wang + * + */ +public class Encrypt { + private Key key; + private byte[] byteMi = null; + private byte[] byteMing = null; + private String strM = ""; + + // 根据参数生成KEY + public void setKey(String strKey) { + try { + KeyGenerator generator = KeyGenerator.getInstance("DES"); + generator.init(new SecureRandom(strKey.getBytes())); + this.key = generator.generateKey(); + generator = null; + } catch (Exception e) { + e.printStackTrace(); + } + + } + + // 解密:以String密文输入,String明文输出 + public void setDesString(String strMi) { + BASE64Decoder base64De = new BASE64Decoder(); + try { + this.byteMi = base64De.decodeBuffer(strMi); + this.byteMing = this.getDesCode(byteMi); + this.strM = new String(byteMing, "UTF8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + base64De = null; + byteMing = null; + byteMi = null; + } + } + + // 解密以byte[]密文输入,以byte[]明文输出 + private byte[] getDesCode(byte[] byteD) { + Cipher cipher; + byte[] byteFina = null; + try { + cipher = Cipher.getInstance("DES"); + cipher.init(Cipher.DECRYPT_MODE, key); + byteFina = cipher.doFinal(byteD); + } catch (Exception e) { + e.printStackTrace(); + } finally { + cipher = null; + } + return byteFina; + } + + // 返回解密后的明文 + public String getStrM() { + return strM; + } +} \ No newline at end of file diff --git a/src/com/jerry/mail/SendMail.java b/src/com/jerry/mail/SendMail.java new file mode 100644 index 0000000..de10d33 --- /dev/null +++ b/src/com/jerry/mail/SendMail.java @@ -0,0 +1,343 @@ +/** + * 文件名称 : SendMail.java + * 项 目 名 : JavaMailWeb + * 包 名 : com.jerry.mail.model + * 版权所有 : 版权所有(C)2012-2013 + * 创建作者 : Jerry Wang + * 创建时间 : May 17, 2013 9:55:52 AM + * 电子邮件 : jerry002@126.com + * 当前版本 : v1.0 + */ +package com.jerry.mail; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.Properties; +import java.util.StringTokenizer; + +import javax.activation.DataHandler; +import javax.activation.FileDataSource; +import javax.mail.Address; +import javax.mail.BodyPart; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; +import javax.mail.internet.MimeUtility; +/** + * SendMail.java + * 发送邮件类 + * @author Jerry Wang + * May 17, 2013 9:55:52 AM + */ +public class SendMail { + private static String SMTPHost = ""; // SMTP服务器 + private static String username = ""; // 登录SMTP服务器的帐号 + private static String password = ""; // 登录SMTP服务器的密码 + private static String from = ""; // 发件人邮箱 + + private Address[] to = null; // 收件人邮箱 + private String subject = ""; // 邮件标题 + private String content = ""; // 邮件内容 + private Address[] copyto = null;// 抄送邮件到 + private Session mailSession = null; + private Transport transport = null; + private ArrayList filename = new ArrayList(); // 附件文件名 + private static SendMail sendMail = null; + private final static String charset = "UTF-8"; + + /** + * @Name : SendMail + * @Description : 无参数构造方法 + * @param : + * @author : Jerry Wang + * @DateTime : May 17, 2013 9:59:47 AM + */ + private SendMail() {} + + /** + * @Name : getMailInstantiate + * @Description : 返回SendMail的对象 + * @param : @return + * @return : SendMail + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:02:46 AM + */ + public static SendMail getInstance() { + if(null == sendMail) { + synchronized (SendMail.class) { + if(null == sendMail) { + init(); + sendMail = new SendMail(); + } + } + } + return sendMail; + } + + private synchronized static void init() { + SMTPHost = "smtp.126.com"; + username = "jerry002@126.com"; + from = username; + password = getPassword(); + } + + /** + * @Name : connect + * @Description : 连接SMTP邮件服务器 + * @param : + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:16:13 AM + */ + public void connect() { + try { + if(transport == null || !transport.isConnected()) { + synchronized (this) { + if(transport == null || !transport.isConnected()) { + // 创建一个属性对象 + Properties props = new Properties(); + // 指定SMTP服务器 + props.put("mail.smtp.host", SMTPHost); + // 指定是否需要SMTP验证 + props.put("mail.smtp.auth", "true"); + // 创建一个授权验证对象 + SmtpPop3Auth auth = new SmtpPop3Auth(); + auth.setAccount(username, password); + // 创建一个Session对象 + mailSession = Session.getDefaultInstance(props, auth); + // 设置是否调试 + mailSession.setDebug(false); + // if (transport != null) + // 关闭连接 + // transport.close(); + // 创建一个Transport对象 + transport = mailSession.getTransport("smtp"); + // 连接SMTP服务器 + transport.connect(SMTPHost, username, password); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * @Name : close + * @Description : 关闭连接SMTP邮件服务器 + * @param : @return + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:18:19 AM + */ + public void close() { + try { + if(transport.isConnected()) { + synchronized (SendMail.class) { + if(transport.isConnected()) { + transport.close(); + transport = null; + } + } + } + } catch (MessagingException e) { + e.printStackTrace(); + } + } + + /** + * @Name : send + * @Description : 发送邮件 + * @param : @return + * @return : String + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:18:19 AM + */ + public synchronized boolean send() { + boolean result = false; + try { + // 连接smtp服务器 + sendMail.connect(); + // 创建一个MimeMessage 对象 + MimeMessage message = new MimeMessage(mailSession); + + // 指定发件人邮箱 + message.setFrom(new InternetAddress(from)); + // 指定收件人邮箱 + message.addRecipients(Message.RecipientType.TO, to); + if (!"".equals(copyto)) + // 指定抄送人邮箱 + message.addRecipients(Message.RecipientType.CC, copyto); + // 指定邮件主题 + message.setSubject(subject); + // 指定邮件发送日期 + message.setSentDate(new Date()); + // 指定邮件优先级 1:紧急 3:普通 5:缓慢 + message.setHeader("X-Priority", "3"); + message.saveChanges(); + // 判断附件是否为空 + if (!filename.isEmpty()) { + // 新建一个MimeMultipart对象用来存放多个BodyPart对象 + Multipart container = new MimeMultipart(); + // 新建一个存放信件内容的BodyPart对象 + BodyPart textBodyPart = new MimeBodyPart(); + // 给BodyPart对象设置内容和格式/编码方式 + textBodyPart.setContent(content, "text/html;charset="+charset); + // 将含有信件内容的BodyPart加入到MimeMultipart对象中 + container.addBodyPart(textBodyPart); + Iterator fileIterator = filename.iterator(); + while (fileIterator.hasNext()) {// 迭代所有附件 + String attachmentString = fileIterator.next(); + // 新建一个存放信件附件的BodyPart对象 + BodyPart fileBodyPart = new MimeBodyPart(); + // 将本地文件作为附件 + FileDataSource fds = new FileDataSource(attachmentString); + fileBodyPart.setDataHandler(new DataHandler(fds)); + // 处理邮件中附件文件名的中文问题 + String attachName = fds.getName(); + attachName = MimeUtility.encodeText(attachName); + // 设定附件文件名 + fileBodyPart.setFileName(attachName); + // 将附件的BodyPart对象加入到container中 + container.addBodyPart(fileBodyPart); + } + // 将container作为消息对象的内容 + message.setContent(container); + } else {// 没有附件的情况 + message.setContent(content, "text/html;charset="+charset); + } + // 发送邮件 + Transport.send(message, message.getAllRecipients()); + if (transport != null) + transport.close(); + result = true; + } catch (Exception e) { + e.printStackTrace(); + } finally { + sendMail.close(); + } + + return result; + } + + /** + * @Name : setContent + * @Description : 设置邮件内容 + * @param : @param content + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:07:30 AM + */ + public void setContent(String content) { + this.content = content; + } + + /** + * @Name : setFilename + * @Description : 设置附件名称 + * @param : @param filename + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:08:27 AM + */ + public void setFilename(ArrayList filename) { + try { + Iterator iterator = filename.iterator(); + ArrayList attachArrayList = new ArrayList(); + while (iterator.hasNext()) { + String attachment = iterator.next(); + // 解决文件名的中文问题 + attachment = MimeUtility.decodeText(attachment); + // 将文件路径中的'\'替换成'/' + attachment = attachment.replaceAll("\\\\", "/"); + attachArrayList.add(attachment); + } + this.filename = attachArrayList; + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * @Name : setSubject + * @Description : 设置标题 + * @param : @param subject + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:08:44 AM + */ + public void setSubject(String subject) { + try { + // 解决标题的中文问题 + subject = MimeUtility.encodeText(subject); + this.subject = subject; + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * @Name : setTo + * @Description : 设置收件人邮箱 + * @param : @param toto + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:09:09 AM + */ + public void setTo(String toto) { + try { + int i = 0; + StringTokenizer tokenizer = new StringTokenizer(toto, ";"); + to = new Address[tokenizer.countTokens()];// 动态的决定数组的长度 + while (tokenizer.hasMoreTokens()) { + String d = tokenizer.nextToken(); + + d = MimeUtility.encodeText(d); + to[i] = new InternetAddress(d);// 将字符串转换为整型 + + i++; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * @Name : setCopy_to + * @Description : 设置抄送 + * @param : @param copyTo + * @return : void + * @author : Jerry Wang + * @DateTime : May 17, 2013 10:09:38 AM + */ + public void setCopyto(String copyTo) { + try { + int i = 0; + StringTokenizer tokenizer = new StringTokenizer(copyTo, ";"); + copyto = new Address[tokenizer.countTokens()];// 动态的决定数组的长度 + while (tokenizer.hasMoreTokens()) { + String tolen = tokenizer.nextToken(); + tolen = MimeUtility.encodeText(tolen); + copyto[i] = new InternetAddress(tolen);// 将字符串转换为整型 + i++; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static String getPassword() { + Encrypt encrypt = new Encrypt(); + encrypt.setKey(username); + encrypt.setDesString("V2fwg3wuUDEI4xUTpYbzSA=="); + return encrypt.getStrM(); + } + +} diff --git a/src/com/jerry/mail/SendMailService.java b/src/com/jerry/mail/SendMailService.java new file mode 100644 index 0000000..202b862 --- /dev/null +++ b/src/com/jerry/mail/SendMailService.java @@ -0,0 +1,5 @@ +package com.jerry.mail; + +public interface SendMailService { + public void sendMail(String to, String subject, String content); +} diff --git a/src/com/jerry/mail/SendMailServiceImpl.java b/src/com/jerry/mail/SendMailServiceImpl.java new file mode 100644 index 0000000..162e4c2 --- /dev/null +++ b/src/com/jerry/mail/SendMailServiceImpl.java @@ -0,0 +1,31 @@ +package com.jerry.mail; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +public class SendMailServiceImpl implements SendMailService { + + @Override + public void sendMail(final String to, final String subject, final String content) { + ThreadPoolExecutor taskExecutor = new ScheduledThreadPoolExecutor(10); + taskExecutor.execute(new Runnable() { + + @Override + public void run() { + synchronized (SendMailServiceImpl.class) { + SendMail sendMail = SendMail.getInstance(); + sendMail.setSubject(subject); + sendMail.setTo(to); + sendMail.setContent(content); + long start = System.currentTimeMillis(); + sendMail.send(); + long end = System.currentTimeMillis(); + System.out.println("用时 :" + (end - start) + "ms"); + System.out.println(Thread.currentThread() + "发送完成"); + } + } + }); + } + + +} diff --git a/src/com/jerry/mail/SmtpPop3Auth.java b/src/com/jerry/mail/SmtpPop3Auth.java new file mode 100644 index 0000000..cfacf63 --- /dev/null +++ b/src/com/jerry/mail/SmtpPop3Auth.java @@ -0,0 +1,20 @@ +package com.jerry.mail; + +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; + +public class SmtpPop3Auth extends Authenticator { + public String user; + public String password; + + // 设置帐号信息 + public void setAccount(String user, String password) { + this.user = user; + this.password = password; + } + + // 取得PasswordAuthentication对象 + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(user, password); + } +} \ No newline at end of file diff --git a/src/com/jerry/performance/PerformanceTest.java b/src/com/jerry/performance/PerformanceTest.java new file mode 100644 index 0000000..160dee9 --- /dev/null +++ b/src/com/jerry/performance/PerformanceTest.java @@ -0,0 +1,187 @@ +package com.jerry.performance; + +import java.util.Random; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Lock、synchronized、Atomic性能测试 + * @author Wangjiajun + * @Email wangjiajun@58.com + * + */ +public class PerformanceTest { + public static void test(int round, int threadNum) { + new SynchronizedTest("synchronized", round, threadNum).testTime(); + new LockTest("lock", round, threadNum).testTime(); + new AtomicTest("atomic", round, threadNum).testTime(); + } + + public static void main(String[] args) { + for(int i = 0; i < 5; i++) { + int round = 100000 * (i + 1); + int threadNum = 5 * (i + 1); + System.out.println("-------------------------"); + System.out.println("round:" + round + "; thread:" + threadNum); + PerformanceTest.test(round, threadNum); + + } + } +} + +class SynchronizedTest extends Template{ + + public SynchronizedTest(String id, int round, int threadNum) { + super(id, round, threadNum); + } + + @Override + synchronized void sumValue() { + super.countValue += super.preInit[index++%round]; + } + + @Override + synchronized long getValue() { + return super.countValue; + } + +} + +class LockTest extends Template { + ReentrantLock lock = new ReentrantLock(); + + public LockTest(String id, int round, int threadNum) { + super(id, round, threadNum); + } + + @Override + void sumValue() { + try { + lock.lock(); + super.countValue += super.preInit[index++%round]; + } finally { + lock.unlock(); + } + + } + + @Override + long getValue() { + try { + lock.lock(); + return super.countValue; + } finally { + lock.unlock(); + } + + } + +} + +class AtomicTest extends Template{ + + public AtomicTest(String id, int round, int threadNum) { + super(id, round, threadNum); + } + + @Override + void sumValue() { + super.countValueAtmoic.addAndGet(super.preInit[indexAtomic.get()%round]); + } + + @Override + long getValue() { + return super.countValueAtmoic.get(); + } + +} + +abstract class Template { + public String id; + public int round; + public int threadNum; + public long countValue; + public AtomicLong countValueAtmoic = new AtomicLong(0); + public int[] preInit; + public int index; + public AtomicInteger indexAtomic = new AtomicInteger(0); + Random r = new Random(47); + // 任务栅栏,同批任务,先到达wait的任务挂起,一直等到全部任务到达制定的wait地点后,才能全部唤醒,继续执行 + private CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum * 2 + 1); + + public Template(String id, int round, int threadNum) { + this.id = id; + this.round = round; + this.threadNum = threadNum; + preInit = new int[round]; + for (int i = 0; i < preInit.length; i++) { + preInit[i] = r.nextInt(100); + } + } + + abstract void sumValue(); + + /* + * 对long的操作是非原子的,原子操作只针对32位 long是64位, 底层操作的时候分2个32位读写,因此不是线程安全 + */ + abstract long getValue(); + + public void testTime() { + ExecutorService se = Executors.newCachedThreadPool(); + long start = System.nanoTime(); + // 同时开启2*ThreadNum个数的读写线程 + for (int i = 0; i < threadNum; i++) { + se.execute(new Runnable() { + public void run() { + for (int i = 0; i < round; i++) { + sumValue(); + } + + // 每个线程执行完同步方法后就等待 + try { + cyclicBarrier.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + + } + }); + se.execute(new Runnable() { + public void run() { + + getValue(); + try { + // 每个线程执行完同步方法后就等待 + cyclicBarrier.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + + } + }); + } + + try { + // 当前统计线程也wait,所以CyclicBarrier的初始值是threadNum*2+1 + cyclicBarrier.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + e.printStackTrace(); + } + // 所有线程执行完成之后,才会跑到这一步 + long duration = System.nanoTime() - start; + System.out.println(id + " = " + duration + "ms"); + + } + +} diff --git a/src/com/jerry/syncthreadpool/App.java b/src/com/jerry/syncthreadpool/App.java new file mode 100644 index 0000000..83ad5e1 --- /dev/null +++ b/src/com/jerry/syncthreadpool/App.java @@ -0,0 +1,30 @@ +package com.jerry.syncthreadpool; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +/** + * java线程池同步处理 + * @author Jerry Wang + * + */ +public class App { + + public static void main(String[] args) throws InterruptedException, ExecutionException { + + List lists = new ArrayList(); + for (int i = 0; i < 100000; i++) { + lists.add("jerry"+i); + } + + List> callables= SyncThreadPool.getSessionCallable(lists); + List> syncFnData = SyncThreadPool.syncFn(callables); + List results = new ArrayList(); + for (Future future : syncFnData) { + if(future.isDone()){ + results.add(future.get()) ; + } + } + } +} diff --git a/src/com/jerry/syncthreadpool/SessionCallable.java b/src/com/jerry/syncthreadpool/SessionCallable.java new file mode 100644 index 0000000..5309493 --- /dev/null +++ b/src/com/jerry/syncthreadpool/SessionCallable.java @@ -0,0 +1,7 @@ +package com.jerry.syncthreadpool; + +import java.util.concurrent.Callable; + +public abstract class SessionCallable implements Callable{ + +} \ No newline at end of file diff --git a/src/com/jerry/syncthreadpool/SyncThreadPool.java b/src/com/jerry/syncthreadpool/SyncThreadPool.java new file mode 100644 index 0000000..d05aa2e --- /dev/null +++ b/src/com/jerry/syncthreadpool/SyncThreadPool.java @@ -0,0 +1,42 @@ +package com.jerry.syncthreadpool; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +public class SyncThreadPool { + + + public static List> getSessionCallable(List lists){ + List> callables = new LinkedList>(); + if(null != lists && lists.size() > 0){ + for (final String str : lists) { + callables.add(new SessionCallable() { + @Override + public String call() throws Exception { + String temp = str+"123"; + System.err.println(Thread.currentThread()+":"+str+":"+temp); + return temp; + } + }); + } + } + return callables; + } + + + public static List> syncFn(List> callables){ + try { + ExecutorService threadPool = Executors.newFixedThreadPool(5); + if(null!=callables&&callables.size()>0){ + List> Futures = threadPool.invokeAll(callables); + threadPool.shutdown(); + return Futures; + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + return null; + } +} \ No newline at end of file diff --git a/src/com/jerry/thread/BlockingQueueCommunication.java b/src/com/jerry/thread/BlockingQueueCommunication.java new file mode 100644 index 0000000..619bdec --- /dev/null +++ b/src/com/jerry/thread/BlockingQueueCommunication.java @@ -0,0 +1,87 @@ +package com.jerry.thread; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +/** + * 阻塞队列通信 + * @author Jerry Wang + * + */ +public class BlockingQueueCommunication { + + /** + * @param args + */ + public static void main(String[] args) { + + final Business business = new Business(); + new Thread( + new Runnable() { + + @Override + public void run() { + + for(int i=1;i<=50;i++){ + business.sub(i); + } + + } + } + ).start(); + + for(int i=1;i<=50;i++){ + business.main(i); + } + + } + + static class Business { + + BlockingQueue queue1 = new ArrayBlockingQueue(1); + BlockingQueue queue2 = new ArrayBlockingQueue(1); + + { +// Collections.synchronizedMap(null); + try { + System.out.println("xxxxxdfsdsafdsa"); + queue2.put(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void sub(int i){ + try { + queue1.put(1); + } catch (InterruptedException e) { + e.printStackTrace(); + } + for(int j=1;j<=10;j++){ + System.out.println("sub thread sequece of " + j + ",loop of " + i); + } + try { + queue2.take(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public void main(int i){ + try { + queue2.put(1); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + for(int j=1;j<=100;j++){ + System.out.println("main thread sequece of " + j + ",loop of " + i); + } + try { + queue1.take(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/com/jerry/thread/BlockingQueueTest.java b/src/com/jerry/thread/BlockingQueueTest.java new file mode 100644 index 0000000..aa0ae57 --- /dev/null +++ b/src/com/jerry/thread/BlockingQueueTest.java @@ -0,0 +1,51 @@ +package com.jerry.thread; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +/** + * 阻塞队列 BlockingQueue + * @author Jerry Wang + * + */ +public class BlockingQueueTest { + public static void main(String[] args) { + final BlockingQueue queue = new ArrayBlockingQueue(3); + for(int i=0;i<2;i++){ + new Thread(){ + public void run(){ + while(true){ + try { + Thread.sleep((long)(Math.random()*1000)); + System.out.println(Thread.currentThread().getName() + "准备放数据!"); + queue.put(1); + System.out.println(Thread.currentThread().getName() + "已经放了数据," + + "队列目前有" + queue.size() + "个数据"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } + } + + }.start(); + } + + new Thread(){ + public void run(){ + while(true){ + try { + //将此处的睡眠时间分别改为100和1000,观察运行结果 + Thread.sleep(1000); + System.out.println(Thread.currentThread().getName() + "准备取数据!"); + queue.take(); + System.out.println(Thread.currentThread().getName() + "已经取走数据," + + "队列目前有" + queue.size() + "个数据"); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + }.start(); + } +} diff --git a/src/com/jerry/thread/BoundedBuffer.java b/src/com/jerry/thread/BoundedBuffer.java new file mode 100644 index 0000000..35f2a0d --- /dev/null +++ b/src/com/jerry/thread/BoundedBuffer.java @@ -0,0 +1,53 @@ +package com.jerry.thread; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 阻塞队列 + * @author Jerry Wang + * + */ +public class BoundedBuffer { + final Lock lock = new ReentrantLock(); + final Condition notFull = lock.newCondition(); + final Condition notEmpty = lock.newCondition(); + + final Object[] items = new Object[100]; + + int putptr, takeptr, count; + + public void put(Object x) throws InterruptedException { + lock.lock(); + + try { + while(count == items.length) + notFull.await(); + items[putptr] = x; + if(++putptr == items.length) + putptr = 0; + ++ count; + notEmpty.signal(); + } finally { + lock.unlock(); + } + } + + public Object take() throws InterruptedException { + try { + lock.lock(); + while(count == 0) + notEmpty.await(); + Object x = items[takeptr]; + if(++takeptr == items.length) + takeptr = 0; + --count; + notFull.signal(); + return x; + } finally { + lock.unlock(); + } + + } +} diff --git a/src/com/jerry/thread/CacheDemo.java b/src/com/jerry/thread/CacheDemo.java new file mode 100644 index 0000000..3ab94ef --- /dev/null +++ b/src/com/jerry/thread/CacheDemo.java @@ -0,0 +1,62 @@ +package com.jerry.thread; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 模拟一个缓存器 + * + * @author Jerry Wang + * + */ +public class CacheDemo { + private Map cache = new HashMap(); + + /** + * 使用 synchronized 进行互斥 + * + * @param key + * @return + */ + // public synchronized Object getData(String key) { + // Object value = cache.get(key); + // if(value == null) { + // value = "xxxxxx"; // 实际是从数据库中取 + // } + // return value; + // } + + /** + * 使用读写锁 + * + * @param key + * @return + */ + private ReadWriteLock lock = new ReentrantReadWriteLock(); + + public Object get(String id) { + Object value = null; + lock.readLock().lock();// 首先开启读锁,从缓存中去取 + try { + value = cache.get(id); + if (value == null) { // 如果缓存中没有释放读锁,上写锁 + lock.readLock().unlock(); + lock.writeLock().lock(); + try { + if (value == null) { + value = "aaa"; // 此时可以去数据库中查找,这里简单的模拟一下 + } + } finally { + lock.writeLock().unlock(); // 释放写锁 + } + lock.readLock().lock(); // 然后再上读锁 + } + } finally { + lock.readLock().unlock(); // 最后释放读锁 + } + return value; + } + +} diff --git a/src/com/jerry/thread/CallableAndFuture.java b/src/com/jerry/thread/CallableAndFuture.java new file mode 100644 index 0000000..b2509e9 --- /dev/null +++ b/src/com/jerry/thread/CallableAndFuture.java @@ -0,0 +1,77 @@ +package com.jerry.thread; + +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Callable与Future的应用 + * @author Jerry Wang + * + */ +public class CallableAndFuture { + public static void singleCallback() { + ExecutorService threadPool = Executors.newSingleThreadExecutor(); + Future future = + threadPool.submit(new Callable () { + + @Override + public String call() throws Exception { + Thread.sleep(2000); + return "hello"; + } + + }); + + System.out.println("等待结果"); + try { + System.out.println("拿到结果" + future.get(3,TimeUnit.SECONDS)); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException e) { + e.printStackTrace(); + } + } + + public static void multiCallback() { + + ExecutorService threadPool2 = Executors.newFixedThreadPool(10); + ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(threadPool2); + for(int i = 0; i < 10; i++) { + final int seq = i; + executorCompletionService.submit(new Callable() { + + @Override + public Integer call() throws Exception { + Thread.sleep(new Random().nextInt(5000)); + return seq; + } + + }); + } + + for(int i = 0; i < 10; i++) { + try { + System.out.println(executorCompletionService.take().get()); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + } + + } + public static void main(String[] args) { +// CallableAndFuture.singleCallback(); + + CallableAndFuture.multiCallback(); + } +} diff --git a/src/com/jerry/thread/ConditionCommunication.java b/src/com/jerry/thread/ConditionCommunication.java new file mode 100644 index 0000000..7a428bb --- /dev/null +++ b/src/com/jerry/thread/ConditionCommunication.java @@ -0,0 +1,79 @@ +package com.jerry.thread; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 使用condition实现线程同步通信技术 + * 子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次, + * 接着再回到主线程又循环100次,如此循环50次 + * @author JerryWang + * + */ +public class ConditionCommunication { + public static void main(String[] args) { + final Business business = new Business(); + new Thread( + new Runnable() { + @Override + public void run() { + for(int i = 1; i <= 50; i++) { + business.sub(i); + } + } + } + ).start(); + + for(int i = 1; i <= 50; i++) { + business.main(i); + } + } + + static class Business{ + Lock lock = new ReentrantLock(); + Condition condition = lock.newCondition(); + private boolean bShouldSub = true; + public void sub(int i) { + lock.lock(); + try { + while(bShouldSub) { + try { + condition.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + for(int j = 1; j <= 10; j++) { + System.out.println("sub thread sequece of " + j + ", loop of " + i); + } + bShouldSub = false; + condition.signal(); + } finally { + lock.unlock(); + } + } + + public void main(int i) { + lock.lock(); + try { + while(!bShouldSub) { + try { + condition.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + for(int j = 1; j <= 100; j++) { + System.out.println("main thread sequece of " + j + ", loop of " + i); + } + bShouldSub = true; + condition.signal(); + } finally { + lock.unlock(); + } + } + } +} + + diff --git a/src/com/jerry/thread/CountdownLatchTest.java b/src/com/jerry/thread/CountdownLatchTest.java new file mode 100644 index 0000000..5621f2c --- /dev/null +++ b/src/com/jerry/thread/CountdownLatchTest.java @@ -0,0 +1,48 @@ +package com.jerry.thread; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * CountDownLatch同步工具 + * @author Jerry Wang + * + */ +public class CountdownLatchTest { + + public static void main(String[] args) { + ExecutorService service = Executors.newCachedThreadPool(); + final CountDownLatch cdOrder = new CountDownLatch(1); + final CountDownLatch cdAnswer = new CountDownLatch(3); + for(int i=0;i<3;i++){ + Runnable runnable = new Runnable(){ + public void run(){ + try { + System.out.println("线程" + Thread.currentThread().getName() + "正准备接受命令"); + cdOrder.await(); + System.out.println("线程" + Thread.currentThread().getName() + "已接受命令"); + Thread.sleep((long)(Math.random()*10000)); + System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果"); + cdAnswer.countDown(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + service.execute(runnable); + } + try { + Thread.sleep((long)(Math.random()*10000)); + + System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令"); + cdOrder.countDown(); + System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果"); + cdAnswer.await(); + System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果"); + } catch (Exception e) { + e.printStackTrace(); + } + service.shutdown(); + + } +} diff --git a/src/com/jerry/thread/CyclicBarrierTest.java b/src/com/jerry/thread/CyclicBarrierTest.java new file mode 100644 index 0000000..c765150 --- /dev/null +++ b/src/com/jerry/thread/CyclicBarrierTest.java @@ -0,0 +1,42 @@ +package com.jerry.thread; + +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * CyclicBarrier同步工具 + * @author Jerry Wang + * + */ +public class CyclicBarrierTest { + public static void main(String[] args) { + ExecutorService service = Executors.newCachedThreadPool(); + final CyclicBarrier cb = new CyclicBarrier(3); + for(int i=0;i<3;i++){ + Runnable runnable = new Runnable(){ + public void run(){ + try { + Thread.sleep((long)(Math.random()*10000)); + System.out.println("线程" + Thread.currentThread().getName() + + "即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); + cb.await(); + + Thread.sleep((long)(Math.random()*10000)); + System.out.println("线程" + Thread.currentThread().getName() + + "即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); + cb.await(); + Thread.sleep((long)(Math.random()*10000)); + System.out.println("线程" + Thread.currentThread().getName() + + "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); + cb.await(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + service.execute(runnable); + } + service.shutdown(); + } +} diff --git a/src/com/jerry/thread/ExchangerTest.java b/src/com/jerry/thread/ExchangerTest.java new file mode 100644 index 0000000..1d6f77a --- /dev/null +++ b/src/com/jerry/thread/ExchangerTest.java @@ -0,0 +1,49 @@ +package com.jerry.thread; +import java.util.concurrent.Exchanger; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Exchanger同步工具 + * @author Jerry Wang + * + */ +public class ExchangerTest { + + public static void main(String[] args) { + ExecutorService service = Executors.newCachedThreadPool(); + final Exchanger exchanger = new Exchanger(); + service.execute(new Runnable(){ + public void run() { + try { + + String data1 = "zxx"; + System.out.println("线程" + Thread.currentThread().getName() + + "正在把数据" + data1 +"换出去"); + Thread.sleep((long)(Math.random()*10000)); + String data2 = (String)exchanger.exchange(data1); + System.out.println("线程" + Thread.currentThread().getName() + + "换回的数据为" + data2); + }catch(Exception e){ + + } + } + }); + service.execute(new Runnable(){ + public void run() { + try { + + String data1 = "lhm"; + System.out.println("线程" + Thread.currentThread().getName() + + "正在把数据" + data1 +"换出去"); + Thread.sleep((long)(Math.random()*10000)); + String data2 = (String)exchanger.exchange(data1); + System.out.println("线程" + Thread.currentThread().getName() + + "换回的数据为" + data2); + }catch(Exception e){ + + } + } + }); + } +} diff --git a/src/com/jerry/thread/ReadWriteLockTest.java b/src/com/jerry/thread/ReadWriteLockTest.java new file mode 100644 index 0000000..7896004 --- /dev/null +++ b/src/com/jerry/thread/ReadWriteLockTest.java @@ -0,0 +1,72 @@ +package com.jerry.thread; + +import java.util.Random; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 读写锁 + * @author Jerry Wang + * + */ +public class ReadWriteLockTest { + public static void main(String[] args) { + final Queue queue = new Queue(); + for (int i = 0; i < 3; i++) { + new Thread() { + @Override + public void run() { + while(true) { + queue.get(); + } + } + }.start(); + + new Thread() { + @Override + public void run() { + while(true) { + queue.put(new Random().nextInt(10000)); + } + } + }.start(); + } + } +} + + +class Queue { + private Object data = null; + ReadWriteLock lock = new ReentrantReadWriteLock(); + public void get() { + lock.readLock().lock(); + try { + System.out.println(Thread.currentThread().getName() + " be ready to read data :" + data); + + Thread.sleep((long) (Math.random() * 1000)); + + System.out.println(Thread.currentThread().getName() + " have read data : " + data); + + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.readLock().unlock(); + } + + } + + public void put(Object data) { + lock.writeLock().lock(); + try { + System.out.println(Thread.currentThread().getName() + " be ready to write data :" + data); + + Thread.sleep((long)(Math.random() * 1000)); + + System.out.println(Thread.currentThread().getName() + " have write data : " + data); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.writeLock().unlock(); + } + } +} diff --git a/src/com/jerry/thread/SemaphoreTest.java b/src/com/jerry/thread/SemaphoreTest.java new file mode 100644 index 0000000..4ae888b --- /dev/null +++ b/src/com/jerry/thread/SemaphoreTest.java @@ -0,0 +1,47 @@ +package com.jerry.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Semaphore; + +/** + * Semaphore同步工具 + * @author Jerry Wang + * + */ +public class SemaphoreTest { + public static void main(String[] args) { + ExecutorService service = Executors.newCachedThreadPool(); + final Semaphore semaphore = new Semaphore(3); + for(int i = 0; i < 10; i++) { + Runnable runable = new Runnable() { + + @Override + public void run() { + try { + semaphore.acquire(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + System.out.println("线程" + Thread.currentThread().getName() + "进入," + + "当前已有" + (3 - semaphore.availablePermits() + "个并发")); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("线程" + Thread.currentThread().getName() + "即将离开"); + + semaphore.release(); + + System.out.println("线程" + Thread.currentThread().getName() + "进入," + + "当前已有" + (3 - semaphore.availablePermits() + "个并发")); + + } + }; + service.execute(runable); + } + } +} diff --git a/src/com/jerry/thread/TraditionalThreadSynchronized.java b/src/com/jerry/thread/TraditionalThreadSynchronized.java index d3ad116..95d6c4a 100644 --- a/src/com/jerry/thread/TraditionalThreadSynchronized.java +++ b/src/com/jerry/thread/TraditionalThreadSynchronized.java @@ -1,6 +1,10 @@ package com.jerry.thread; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + /** - * 传统方式实现线程互斥 + * 传统方式实现线程互斥(增加Lock) * @author Jerry Wang * */ @@ -52,12 +56,36 @@ class Outputer{ // } // } - public synchronized void output(String name) { +// public void output(String name) { +// int len = name.length(); +// synchronized(Outputer.class) { +// for(int i = 0; i < len; i++) { +// System.out.print(name.charAt(i)); +// } +// System.out.println(); +// } +// } + +// public synchronized void output(String name) { +// int len = name.length(); +// for(int i = 0; i < len; i++) { +// System.out.print(name.charAt(i)); +// } +// System.out.println(); +// } + + Lock lock = new ReentrantLock(); + public void output(String name) { int len = name.length(); - for(int i = 0; i < len; i++) { - System.out.print(name.charAt(i)); + lock.lock(); + try{ + for(int i = 0; i < len; i++) { + System.out.print(name.charAt(i)); + } + System.out.println(); + } finally { + lock.unlock(); } - System.out.println(); } } } diff --git a/src/com/jerry/threadpool/ThreadPool.java b/src/com/jerry/threadpool/ThreadPool.java new file mode 100644 index 0000000..6d68a35 --- /dev/null +++ b/src/com/jerry/threadpool/ThreadPool.java @@ -0,0 +1,105 @@ +package com.jerry.threadpool; + +import java.util.LinkedList; + +/** + * Java线程池工具类 + * @author Jerry Wang + * + */ +public class ThreadPool extends ThreadGroup { + private boolean isClosed = false; //线程池是否关闭 + private LinkedList workQueue; //工作队列 + private static int threadPoolID = 1; //线程池的id + public ThreadPool(int poolSize) { //poolSize 表示线程池中的工作线程的数量 + + super(threadPoolID + ""); //指定ThreadGroup的名称 + setDaemon(true); //继承到的方法,设置是否守护线程池 + workQueue = new LinkedList(); //创建工作队列 + for(int i = 0; i < poolSize; i++) { + new WorkThread(i).start(); //创建并启动工作线程,线程池数量是多少就创建多少个工作线程 + } + } + + /** 向工作队列中加入一个新任务,由工作线程去执行该任务*/ + public synchronized void execute(Runnable task) { + if(isClosed) { + throw new IllegalStateException(); + } + if(task != null) { + workQueue.add(task);//向队列中加入一个任务 + notify(); //唤醒一个正在getTask()方法中待任务的工作线程 + } + } + + /** 从工作队列中取出一个任务,工作线程会调用此方法*/ + private synchronized Runnable getTask(int threadid) throws InterruptedException { + while(workQueue.size() == 0) { + if(isClosed) return null; + System.out.println("工作线程"+threadid+"等待任务..."); + wait(); //如果工作队列中没有任务,就等待任务 + } + System.out.println("工作线程"+threadid+"开始执行任务..."); + return (Runnable) workQueue.removeFirst(); //反回队列中第一个元素,并从队列中删除 + } + + /** 关闭线程池 */ + public synchronized void closePool() { + if(! isClosed) { + waitFinish(); //等待工作线程执行完毕 + isClosed = true; + workQueue.clear(); //清空工作队列 + interrupt(); //中断线程池中的所有的工作线程,此方法继承自ThreadGroup类 + } + } + + /** 等待工作线程把所有任务执行完毕*/ + public void waitFinish() { + synchronized (this) { + isClosed = true; + notifyAll(); //唤醒所有还在getTask()方法中等待任务的工作线程 + } + Thread[] threads = new Thread[activeCount()]; //activeCount() 返回该线程组中活动线程的估计值。 + int count = enumerate(threads); //enumerate()方法继承自ThreadGroup类,根据活动线程的估计值获得线程组中当前所有活动的工作线程 + for(int i =0; i < count; i++) { //等待所有工作线程结束 + try { + threads[i].join(); //等待工作线程结束 + }catch(InterruptedException ex) { + ex.printStackTrace(); + } + } + } + + /** + * 内部类,工作线程,负责从工作队列中取出任务,并执行 + * @author sunnylocus + */ + private class WorkThread extends Thread { + private int id; + public WorkThread(int id) { + //父类构造方法,将线程加入到当前ThreadPool线程组中 + super(ThreadPool.this,id+""); + this.id =id; + } + + @Override + public void run() { + while(! isInterrupted()) { //isInterrupted()方法继承自Thread类,判断线程是否被中断 + Runnable task = null; + try { + task = getTask(id); //取出任务 + }catch(InterruptedException ex) { + ex.printStackTrace(); + } + //如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程 + if(task == null) return; + + try { + task.run(); //运行任务 + }catch(Throwable t) { + t.printStackTrace(); + } + }// end while + }// end run + }// end workThread +} \ No newline at end of file diff --git a/src/com/jerry/threadpool/ThreadPoolTest.java b/src/com/jerry/threadpool/ThreadPoolTest.java new file mode 100644 index 0000000..40e238d --- /dev/null +++ b/src/com/jerry/threadpool/ThreadPoolTest.java @@ -0,0 +1,32 @@ +package com.jerry.threadpool; + + +/** + * Java线程池工具类测试 + * @author Jerry Wang + * + */ +public class ThreadPoolTest { + + public static void main(String[] args) throws InterruptedException { + ThreadPool threadPool = new ThreadPool(3); //创建一个有个3工作线程的线程池 + Thread.sleep(500); //休眠500毫秒,以便让线程池中的工作线程全部运行 + //运行任务 + for (int i = 0; i <=5 ; i++) { //创建6个任务 + threadPool.execute(createTask(i)); + } + threadPool.waitFinish(); //等待所有任务执行完毕 + threadPool.closePool(); //关闭线程池 + + } + + private static Runnable createTask(final int taskID) { + return new Runnable() { + public void run() { + // System.out.println("Task" + taskID + "开始"); + System.out.println("Hello world"); + // System.out.println("Task" + taskID + "结束"); + } + }; + } +} diff --git a/src/com/jerry/wait/ThreadWait.java b/src/com/jerry/wait/ThreadWait.java new file mode 100644 index 0000000..dfeb03b --- /dev/null +++ b/src/com/jerry/wait/ThreadWait.java @@ -0,0 +1,207 @@ +package com.jerry.wait; + +/** + * 线程等待的几种方法 + */ +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class ThreadWait { + final static SimpleDateFormat sdf = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + + public static void main(String[] args) throws Exception { + join(); + + } + + private void doSomeWork() { + try { + Thread.sleep((long) (Math.random() * 10000)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public static void doSuperWork() { + System.out.println("Super Worker begin at " + sdf.format(new Date())); + try { + Thread.sleep((long) (Math.random() * 10000)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Super Worker end at " + sdf.format(new Date())); + } + + static class JoinWorker extends Thread { + String workerName; + + public JoinWorker(String workerName) { + this.workerName = workerName; + } + + public void run() { + System.out.println("Sub Worker " + workerName + + " do work begin at " + sdf.format(new Date())); + new ThreadWait().doSomeWork();// 做实际工作 + System.out.println("Sub Worker " + workerName + + " do work complete at " + sdf.format(new Date())); + } + } + + /** + * 使用线程自带的join方法,将子线程加到主线程中 主线程需要等待子线程完成才继续执行 + * + * @throws InterruptedException + */ + public static void join() throws InterruptedException { + System.out.println("=========Test with join====="); + JoinWorker worker1 = new JoinWorker("worker1"); + JoinWorker worker2 = new JoinWorker("worker2"); + worker1.start(); + worker2.start(); + worker1.join(); + worker2.join(); + doSuperWork(); + } + + /** + * 使用CountDownLatch,每个线程调用其countDown方法使计数器-1, + * 主线程调用await方法阻塞等待,直到CountDownLatch计数器为0时继续执行 + * + * @throws InterruptedException + */ + public static void countDownLatch() throws InterruptedException { + System.out.println("=========Test with CountDownLatch====="); + CountDownLatch latch = new CountDownLatch(2); + CountDownLatchWorker worker1 = new CountDownLatchWorker("worker1",latch); + CountDownLatchWorker worker2 = new CountDownLatchWorker("worker2",latch); + worker1.start(); + worker2.start(); + // 主线程阻塞等待 + latch.await(); + doSuperWork(); + } + + /** + * CyclicBarrier类似于CountDownLatch也是个计数器, 不同的是CyclicBarrier的await() + * 方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。 + * 在这之后,如果再次调用 await() 方法,计数就又会变成 N-1,新一轮重新开始 + * CyclicBarrier初始时还可带一个Runnable的参数, + * 此Runnable任务在CyclicBarrier的数目达到后,所有其它线程被唤醒前被执行。 + */ + public static void cyclicBarrier() throws InterruptedException, + BrokenBarrierException { + System.out.println("=========Test with CyclicBarrier====="); + CyclicBarrier cb = new CyclicBarrier(2, new Runnable() { + // 将主线程业务放到CyclicBarrier构造方法中,所有线程都到达Barrier时执行 + @SuppressWarnings("static-access") + public void run() { + new ThreadWait().doSuperWork(); + } + });// 设定需要等待两个线程 + ExecutorService executor = Executors.newFixedThreadPool(2); + CyclicBarrierWorker worker1 = new CyclicBarrierWorker("worker1", cb); + CyclicBarrierWorker worker2 = new CyclicBarrierWorker("worker2", cb); + executor.execute(worker1); + executor.execute(worker2); + executor.shutdown(); + } + + /** + * 使用ExecutorService的invokeAll方法调研callable集合,批量执行多个线程 + * 在invokeAll方法结束之后,再执行主线程其他业务逻辑 + * + * @throws InterruptedException + */ + public static void callable() throws InterruptedException { + System.out.println("=========Test with Callable====="); + List> callList = new ArrayList>(); + ExecutorService exec = Executors.newFixedThreadPool(2); + // 采用匿名内部类实现 + callList.add(new Callable() { + public Integer call() throws Exception { + System.out.println("Sub Worker worker1 do work begin at " + + sdf.format(new Date())); + new ThreadWait().doSomeWork();// 做实际工作 + System.out.println("Sub Worker worker1 do work complete at " + + sdf.format(new Date())); + return 0; + } + }); + callList.add(new Callable() { + public Integer call() throws Exception { + System.out.println("Sub Worker worker2 do work begin at " + + sdf.format(new Date())); + new ThreadWait().doSomeWork();// 做实际工作 + System.out.println("Sub Worker worker2 do work complete at " + + sdf.format(new Date())); + return 0; + } + }); + exec.invokeAll(callList); + exec.shutdown(); + doSuperWork(); + + } + + static class CountDownLatchWorker extends Thread { + String workerName; + + CountDownLatch latch; + + public CountDownLatchWorker(String workerName, CountDownLatch latch) { + this.workerName = workerName; + this.latch = latch; + } + + public void run() { + System.out.println("Sub Worker " + workerName + + " do work begin at " + sdf.format(new Date())); + new ThreadWait().doSomeWork();// 做实际工作 + System.out.println("Sub Worker " + workerName + + " do work complete at " + sdf.format(new Date())); + latch.countDown();// 完成之后,计数器减一 + + } + } + + static class CyclicBarrierWorker extends Thread { + String workerName; + + CyclicBarrier cb; + + public CyclicBarrierWorker(String workerName, CyclicBarrier cb) { + super(); + this.workerName = workerName; + this.cb = cb; + } + + public void run() { + System.out.println("Sub Worker " + workerName + + " do work begin at " + sdf.format(new Date())); + new ThreadWait().doSomeWork();// 做实际工作 + System.out.println("Sub Worker " + workerName + + " do work complete at " + sdf.format(new Date())); + try { + // 等待其他未完成线程 + cb.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (BrokenBarrierException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + } + +} \ No newline at end of file