3.模拟客户端ConnectionRunner获取、使用、最后释放连接的过程,当他使用时连接将会增加获取到连接的数量,反之,将会增加未获取到连接的数量,如下:
package com.atguigu.ct.producer.Test.BB; import java.sql.Connection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; public class ConnectionPoolTest { static ConnectionPool pool = new ConnectionPool(10); //保证所有的ConnectionRunner 能够同时开始 static CountDownLatch start = new CountDownLatch(1); //main 线程将会等待所有 ConnectionRunner 结束才能继续执行 static CountDownLatch end; public static void main(String[] args) throws InterruptedException { //线程数量,可以修改线程数量进行观察 int threadCount = 100; end = new CountDownLatch(threadCount); int count = 20; AtomicInteger got = new AtomicInteger(); AtomicInteger notGot = new AtomicInteger(); for (int i = 0; i < threadCount; i++) { Thread thread = new Thread(new ConnetionRunner(count, got, notGot), "ConnetionRunnerThread"); thread.start(); } start.countDown(); end.await(); System.out.println("total invoke:" + (threadCount * count)); System.out.println(" got connection : " + got); System.out.println(" not got connection : " + notGot); } static class ConnetionRunner implements Runnable { int count; AtomicInteger got; AtomicInteger notGot; public ConnetionRunner(int count, AtomicInteger got, AtomicInteger notGot) { this.count = count; this.got = got; this.notGot = notGot; } @Override public void run() { try { start.await(); } catch (InterruptedException e) { } while (count > 0) { try { //从线程池中获取连接,如果1000ms内无法获取到,将会返回null //分别统计连接获取的数量got和未获取到的数量 notGot Connection connection = pool.fetchConnection(1000); if (connection != null) { try { connection.createStatement(); connection.commit(); } finally { pool.releaseConnection(connection); got.incrementAndGet(); } } else { notGot.incrementAndGet(); } } catch (Exception e) { e.printStackTrace(); } finally { count--; } } end.countDown(); } } } 复制代码
下面通过使用前一节中的线程池来构造一个简单的Web服务器,这个Web服务器用来处理 HTTP请求,目前只能处理简单的文本和JPG图片内容。这个Web服务器使用main线程不断地接 受客户端Socket的连接,将连接以及请求提交给线程池处理,这样使得Web服务器能够同时处 理多个客户端请求,示例如下所示。
public class SimpleHttpServer { private int port=8080; private ServerSocketChannel serverSocketChannel = null; private ExecutorService executorService; private static final int POOL_MULTIPLE = 4; public SimpleHttpServer() throws IOException { executorService= Executors.newFixedThreadPool( Runtime.getRuntime().availableProcessors() * POOL_MULTIPLE); serverSocketChannel= ServerSocketChannel.open(); serverSocketChannel.socket().setReuseAddress(true); serverSocketChannel.socket().bind(new InetSocketAddress(port)); System.out.println("ddd"); } public void service() { while (true) { SocketChannel socketChannel=null; try { socketChannel = serverSocketChannel.accept(); executorService.execute(new Handler(socketChannel)); }catch (IOException e) { e.printStackTrace(); } } } public static void main(String args[])throws IOException { new SimpleHttpServer().service(); } class Handler implements Runnable{ private SocketChannel socketChannel; public Handler(SocketChannel socketChannel){ this.socketChannel=socketChannel; } public void run(){ handle(socketChannel); } public void handle(SocketChannel socketChannel){ try { Socket socket=socketChannel.socket(); System.out.println("ddd" + socket.getInetAddress() + ":" +socket.getPort()); ByteBuffer buffer=ByteBuffer.allocate(1024); socketChannel.read(buffer); buffer.flip(); String request=decode(buffer); System.out.print(request); StringBuffer sb=new StringBuffer("HTTP/1.1 200 OK\r\n"); sb.append("Content-Type:text/html\r\n\r\n"); socketChannel.write(encode(sb.toString())); FileInputStream in; String firstLineOfRequest=request.substring(0,request.indexOf("\r\n")); if(firstLineOfRequest.indexOf("login.htm")!=-1) in=new FileInputStream("/Users/tokou/Documents/post.html"); else in=new FileInputStream("/Users/tokou/Documents/post.html"); FileChannel fileChannel=in.getChannel(); fileChannel.transferTo(0,fileChannel.size(),socketChannel); fileChannel.close(); }catch (Exception e) { e.printStackTrace(); }finally { try{ if(socketChannel!=null)socketChannel.close(); }catch (IOException e) {e.printStackTrace();} } } private Charset charset=Charset.forName("GBK"); public String decode(ByteBuffer buffer){ CharBuffer charBuffer= charset.decode(buffer); return charBuffer.toString(); } public ByteBuffer encode(String str){ return charset.encode(str); } } } 复制代码
面试题
2个线程交替打印A1B2C3D4...这样的模式的实现
方法一 LockSupport
public class TestLockSupport { static Thread t1=null,t2=null; public static void main(String[] args) { char[] aI="1234567".toCharArray(); char[] aC="ABCDEFG".toCharArray(); t1=new Thread(()->{ for (char c : aI) { System.out.println(c); LockSupport.unpark(t2); LockSupport.park(); } },"t1"); t2=new Thread(()->{ for (char c : aC) { LockSupport.park(); System.out.println(c); LockSupport.unpark(t1); } },"t1"); t1.start(); t2.start(); } } 复制代码
结果
1 A 2 B 3 C 4 D 5 E 6 F 7 G 复制代码
方法二 用CAS自旋锁+volatitle来实现
enum ReadyToRun {T1,T2} //先定义T1准备运行 而且要设置volatile 线程可见 static volatile ReadyToRun r=ReadyToRun.T1; public static void main(String[] args) { char[] aI="1234567".toCharArray(); char[] aC="ABCDEFG".toCharArray(); new Thread(()->{ for (char c : aI) { //如果不是T1准备运行 就一直返回空,直到T1运行打印,打印完之后把准备运行的变为T2 while (r!=ReadyToRun.T1){} System.out.println(c); r=ReadyToRun.T2; } },"t1").start(); new Thread(()->{ for (char c : aC) { //如果不是T2准备运行 就一直返回空,直到T2运行打印,打印完之后把准备运行的变为T1 while (r!=ReadyToRun.T2){} System.out.println(c); r=ReadyToRun.T1; } },"t1").start(); } 复制代码
结果
1 A 2 B 3 C 4 D 5 E 6 F 7 G 复制代码
方法三 原子类 AtomicInteger
public class TestLockSupport { //定义一个原子性的对象 static AtomicInteger thredNo=new AtomicInteger(1); public static void main(String[] args) { char[] aI="1234567".toCharArray(); char[] aC="ABCDEFG".toCharArray(); new Thread(()->{ for (char c : aI) { //如果不是1就一直返回空,直到运行打印,打印完之后把原子对象变成2 while (thredNo.get()!=1){} System.out.println(c); thredNo.set(2); } },"t1").start(); new Thread(()->{ for (char c : aC) { //如果不是2就一直返回空,直到运行打印,打印完之后把原子对象变成1 while (thredNo.get()!=2){} System.out.println(c); thredNo.set(1); } },"t1").start(); } } 复制代码
方法四 也是面试官 想考你的 synchronized wait notiyfy
public static void main(String[] args) { final Object o=new Object(); char[] aI="1234567".toCharArray(); char[] aC="ABCDEFG".toCharArray(); new Thread(()->{ synchronized (o){ for (char c : aI) { try { System.out.println(c); o.wait(); o.notify(); } catch (InterruptedException e) { e.printStackTrace(); } } o.notify(); } },"t1").start(); new Thread(()->{ synchronized (o){ for (char c : aC) { System.out.println(c); o.notify(); try { o.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } o.notify(); } },"t1").start(); } 复制代码
结尾
多线程的基础就讲到这里了,大家看完这些应该能够知道,线程的基本概况,接下来我们看看并发的锁吧
因为博主也是一个开发萌新 我也是一边学一边写 我有个目标就是一周 二到三篇 希望能坚持个一年吧 希望各位大佬多提意见,让我多学习,一起进步。