• 并发编程(1)


    1、线程基础、线程之间的共享和协作

    基础概念

    CPU核心数和线程数的关系

    核心数:线程数=1:1  ;使用了超线程技术后---> 1:2

    CPU时间片轮转机制

    又称RR调度,会导致上下文切换

    什么是进程和线程

    进程:程序运行资源分配的最小单位,进程内部有多个线程,会共享这个进程的资源

    线程:CPU调度的最小单位,必须依赖进程而存在。

    澄清并行和并发

    并行:同一时刻,可以同时处理事情的能力

    并发:与单位时间相关,在单位时间内可以处理事情的能力

    高并发编程的意义、好处和注意事项

    好处:充分利用cpu的资源、加快用户响应的时间,程序模块化,异步化

    问题:

    线程共享资源,存在冲突;

    容易导致死锁;

    启用太多的线程,就有搞垮机器的可能

    认识Java里的线程

    新启线程的方式

    三种

    1.继承Thread类,2.实现runable接口(无返回值)  3.实现callable接口 (有返回值)

    举例:

    package com.xiangxue.ch1;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    /**
     *@author
     *
     *类说明:如何新建线程
     */
    public class NewThread {
        /*扩展自Thread类*/
        
        /*实现Runnable接口*/
        private static class UseRun implements Runnable{
    
            @Override
            public void run() {
                System.out.println("I am implements Runnable");
            }
            
        }
        
        /*实现Callable接口,允许有返回值*/
        private static class UseCall implements Callable<String>{
    
            @Override
            public String call() throws Exception {
                System.out.println("I am implements Callable");
                return "CallResult";
            }
            
        }    
        
        public static void main(String[] args) 
                throws InterruptedException, ExecutionException {
            
            UseRun useRun = new UseRun();
            new Thread(useRun).start();
            Thread t = new Thread(useRun);
            t.interrupt();
            
            UseCall useCall = new UseCall();
            FutureTask<String> futureTask = new FutureTask<>(useCall);
            new Thread(futureTask).start();
            System.out.println(futureTask.get());
        }
    }

    java本身就是多线程:

    package com.xiangxue.ch1;
    
    import java.lang.management.ManagementFactory;
    import java.lang.management.ThreadInfo;
    import java.lang.management.ThreadMXBean;
    
    /**
     *@author
     *
     *类说明:java的多线程无处不在
     */
    public class OnlyMain {
        public static void main(String[] args) {
            //虚拟机线程管理的接口
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            ThreadInfo[] threadInfos =
                    threadMXBean.dumpAllThreads(false, false);
            for(ThreadInfo threadInfo:threadInfos) {
                System.out.println("["+threadInfo.getThreadId()+"]"+" "
                        +threadInfo.getThreadName());
            }
        }
    }
    
    
    
    
    
    "C:Program FilesJavajdk1.8.0_73injava" "-javaagent:D:DownloadsIntelliJ IDEA 2018.1libidea_rt.jar=52049:D:DownloadsIntelliJ IDEA 2018.1in" -Dfile.encoding=UTF-8 -classpath "D:a_享学享学代码ppt1、第一期课程 ppt 资料(01)并发编程1-2018.05.06-第一节课vip-concurrentin;C:Program FilesJavajdk1.8.0_73jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_73jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_73jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_73jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_73jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_73jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_73jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_73jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_73jrelibext
    ashorn.jar;C:Program FilesJavajdk1.8.0_73jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_73jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_73jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_73jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_73jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_73jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_73jrelibjce.jar;C:Program FilesJavajdk1.8.0_73jrelibjfr.jar;C:Program FilesJavajdk1.8.0_73jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_73jrelibjsse.jar;C:Program FilesJavajdk1.8.0_73jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_73jrelibplugin.jar;C:Program FilesJavajdk1.8.0_73jrelib
    esources.jar;C:Program FilesJavajdk1.8.0_73jrelib
    t.jar;D:a_享学1--并发编程2.线程的并发工具类 (1)commons-lang3-3.9commons-lang3-3.9.jar;D:a_享学1--并发编程2.线程的并发工具类 (1)commons-lang3-3.9-bin.zip" com.xiangxue.ch1.OnlyMain
    [6] Monitor Ctrl-Break
    [5] Attach Listener
    [4] Signal Dispatcher
    [3] Finalizer
    [2] Reference Handler
    [1] main
    
    Process finished with exit code 0

    怎么样才能让Java里的线程安全停止工作呢

    线程自然终止:自然执行完或抛出未处理异常

    stop()resume(),suspend()已不建议使用,stop()会导致线程不会正确释放资源,suspend()容易导致死锁。

    java线程是协作式,而非抢占式

    调用一个线程的interrupt() 方法中断一个线程,并不是强行关闭这个线程,只是跟这个线程打个招呼,将线程的中断标志位置为true,线程是否中断,由线程本身决定。

    isInterrupted() 判定当前线程是否处于中断状态。

    static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false

    方法里如果抛出InterruptedException线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt()

    举例:

    package com.xiangxue.ch1.safeend;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:抛出InterruptedException异常的时候,要注意中断标志位
     */
    public class HasInterrputException {
        
        private static SimpleDateFormat formater 
            = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss_SSS");
        
        private static class UseThread extends Thread{
            
            public UseThread(String name) {
                super(name);
            }
            
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                while(!isInterrupted()) {
                    try {
                        System.out.println("UseThread:"+formater.format(new Date()));
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        System.out.println(threadName+" catch interrput flag is "
                                +isInterrupted()+ " at "
                                +(formater.format(new Date())));
                        interrupt();
                        e.printStackTrace();
                    }
                    System.out.println(threadName);                
                }
                System.out.println(threadName+" interrput flag is "
                        +isInterrupted());
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread endThread = new UseThread("HasInterrputEx");
            endThread.start();
            System.out.println("Main:"+formater.format(new Date()));
            Thread.sleep(800);
            System.out.println("Main begin interrupt thread:"+formater.format(new Date()));
            endThread.interrupt();
            
    
        }
    
    }
    package com.xiangxue.ch1.safeend;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:如何安全的中断线程
     */
    public class EndThread {
        
        private static class UseThread extends Thread{
            
            public UseThread(String name) {
                super(name);
            }
            
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                while(true) {
                    System.out.println(threadName+" is run!");
                }
                //System.out.println(threadName+" interrput flag is "+isInterrupted());
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread endThread = new UseThread("endThread");
            endThread.start();
            Thread.sleep(20);
            endThread.interrupt();
    
        }
    
    }
    package com.xiangxue.ch1.safeend;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:中断Runnable类型的线程
     */
    public class EndRunnable {
        
        private static class UseRunnable implements Runnable{
            
            @Override
            public void run() {
    
                String threadName = Thread.currentThread().getName();
                while(Thread.currentThread().isInterrupted()) {
                    System.out.println(threadName+" is run!");
                }
                System.out.println(threadName+" interrput flag is "
                        +Thread.currentThread().isInterrupted());
            }            
        }
    
        public static void main(String[] args) throws InterruptedException {
            UseRunnable useRunnable = new UseRunnable();
            Thread endThread = new Thread(useRunnable,"endThread");
            endThread.start();
            Thread.sleep(20);
            endThread.interrupt();
        }
    
    }

    Java里的线程再多一点点认识

    线程常用方法和线程的状态

    线程只有5种状态。整个生命周期就是这几种状态的切换。

    run()start() run方法就是普通对象的普通方法,只有调用了start()后,Java才会将线程对象和操作系统中实际的线程进行映射,再来执行run方法。

    yield() :让出cpu的执行权,将线程从运行转到可运行状态,但是下个时间片,该线程依然有可能被再次选中运行。

    线程的优先级

    取值为1~10,缺省为5,但线程的优先级不可靠,不建议作为线程开发时候的手段

    守护线程

    和主线程共死,finally不能保证一定执行

    package com.xiangxue.ch1;
    
    import java.util.concurrent.ExecutionException;
    
    /**
     * @author
     *
     *  类说明:守护线程的使用和守护线程中的finally语句块
     */
    public class DaemonThread {
        
        private static class UseThread extends Thread {
            @Override
            public void run() {
                try {
                    while (!isInterrupted()) {
                        System.out.println(Thread.currentThread().getName()
                                + " I am extends Thread.");
                    }
                    System.out.println(Thread.currentThread().getName() 
                            + " interrupt flag is " + isInterrupted());
                } finally {
                    System.out.println("...........finally");
                }
            }
        }
    
        public static void main(String[] args) throws InterruptedException, 
            ExecutionException {
            UseThread useThread = new UseThread();
            useThread.setDaemon(true);
            useThread.start();
            Thread.sleep(5);
            //useThread.interrupt(); 
        }
    }

    线程间的共享

    synchronized内置锁

    对象锁,锁的是类的对象实例。

    类锁 ,锁的是每个类的的Class对象,每个类的的Class对象在一个虚拟机中只有一个,所以类锁也只有一个。

    举例:

    package com.xiangxue.ch1.syn;
    
    import com.xiangxue.tools.SleepTools;
    
    /**
     *@author
     *Synchronized 关键字
     *类说明:演示对象锁和类锁
     */
    public class SynClzAndInst {
        
        //使用类锁的线程
        private static class SynClass extends Thread{
            @Override
            public void run() {
                System.out.println("TestClass is running...");
                synClass();
            }
        }
    
        //使用对象锁的线程
        private static class InstanceSyn implements Runnable{
            private SynClzAndInst synClzAndInst;
    
            public InstanceSyn(SynClzAndInst synClzAndInst) {
                this.synClzAndInst = synClzAndInst;
            }
    
            @Override
            public void run() {
                System.out.println("TestInstance is running..."+synClzAndInst);
                synClzAndInst.instance();
            }
        }
    
      //使用对象锁的线程
        private static class Instance2Syn implements Runnable{
            private SynClzAndInst synClzAndInst;
    
            public Instance2Syn(SynClzAndInst synClzAndInst) {
                this.synClzAndInst = synClzAndInst;
            }
            @Override
            public void run() {
                System.out.println("TestInstance2 is running..."+synClzAndInst);
                synClzAndInst.instance2();
            }
        }
    
        //锁对象
        private synchronized void instance(){
            SleepTools.second(3);
            System.out.println("synInstance is going..."+this.toString());
            SleepTools.second(3);
            System.out.println("synInstance ended "+this.toString());
        }
        
        //锁对象
        private synchronized void instance2(){
            SleepTools.second(3);
            System.out.println("synInstance2 is going..."+this.toString());
            SleepTools.second(3);
            System.out.println("synInstance2 ended "+this.toString());
        }
    
        //类锁,实际是锁类的class对象
        private static synchronized void synClass(){
            SleepTools.second(1);
            System.out.println("synClass going...");
            SleepTools.second(1);
            System.out.println("synClass end");
        }
    
        public static void main(String[] args) {
            SynClzAndInst synClzAndInst = new SynClzAndInst();
            Thread t1 = new Thread(new InstanceSyn(synClzAndInst));
            
            //SynClzAndInst synClzAndInst2 = new SynClzAndInst();
            //Thread t2 = new Thread(new Instance2Syn(synClzAndInst));
            
            t1.start();
            //t2.start();
            
            SynClass synClass = new SynClass();
            synClass.start();
            SleepTools.second(1);
        }
    }

    volatile关键字

    适合于只有一个线程写,多个线程读的场景,因为它只能确保可见性。

    package com.xiangxue.ch1.vola;
    
    import com.xiangxue.tools.SleepTools;
    
    /**
     *@author
     *
     *类说明:演示violate无法提供操作的原子性
     */
    public class VolatileUnsafe {
        
        private static class VolatileVar implements Runnable {
    
            private volatile int a = 0;
            
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                a = a++;
                System.out.println(threadName+":======"+a);
                SleepTools.ms(100);
                a = a+1;
                System.out.println(threadName+":======"+a);
            }
        }
        
        public static void main(String[] args) {
    
            VolatileVar v = new VolatileVar();
    
            Thread t1 = new Thread(v);
            Thread t2 = new Thread(v);
            Thread t3 = new Thread(v);
            Thread t4 = new Thread(v);
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    
    }

    ThreadLocal

    线程变量。可以理解为是个map,类型 Map<Thread,Integer>

    package com.xiangxue.ch1;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:演示ThreadLocal的使用
     */
    public class UseThreadLocal {
        
        //可以理解为 一个map,类型 Map<Thread,Integer>
        static ThreadLocal<Integer> threadLaocl = new ThreadLocal<Integer>(){
            @Override
            protected Integer initialValue() {
                return 1;
            }
        };
    
        /**
         * 运行3个线程
         */
        public void StartThreadArray(){
            Thread[] runs = new Thread[3];
            for(int i=0;i<runs.length;i++){
                runs[i]=new Thread(new TestThread(i));
            }
            for(int i=0;i<runs.length;i++){
                runs[i].start();
            }
        }
        
        /**
         *类说明:测试线程,线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响
         */
        public static class TestThread implements Runnable{
            int id;
            public TestThread(int id){
                this.id = id;
            }
            public void run() {
                System.out.println(Thread.currentThread().getName()+":start");
                Integer s = threadLaocl.get();//获得变量的值
                s = s+id;
                threadLaocl.set(s);
                System.out.println(Thread.currentThread().getName()+":"
                +threadLaocl.get());
                //threadLaocl.remove();
            }
        }
    
        public static void main(String[] args){
            UseThreadLocal test = new UseThreadLocal();
            test.StartThreadArray();
        }
    }

    线程间协作

    轮询难以保证及时性资源开销很大

    等待和通知

    wait()    对象上的方法

    notify/notifyAll  对象上的方法

    等待和通知的标准范式

    等待方

    1、 获取对象的锁;

    2、 循环里判断条件是否满足,不满足调用wait方法,

    3、 条件满足执行业务逻辑

    通知方来说

    1、 获取对象的锁;

    2、 改变条件

    3、 通知所有等待在对象的线程

    notifynotifyAll应该用谁?

    应该尽量使用notifyAll,使用notify因为有可能发生信号丢失的的情况

    等待超时模式实现一个连接池

    假设  等待时间时长为T,当前时间now+T以后超时

    long  overtime = now+T;

    long remain = T;//等待的持续时间

    while(result不满足条件&& remain>0){

    wait(remain);

    remain = overtime – now;//等待剩下的持续时间

    }

    return result;

    package com.xiangxue.ch1.pool;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.sql.*;
    import java.util.Map;
    import java.util.Properties;
    import java.util.concurrent.Executor;
    import java.util.concurrent.TimeUnit;
    
    import com.xiangxue.tools.SleepTools;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:实现了数据库连接的实现
     */
    public class SqlConnectImpl implements Connection{
        
        /*拿一个数据库连接*/
        public static final Connection fetchConnection(){
            return new SqlConnectImpl();
        }
    
        @Override
        public boolean isWrapperFor(Class<?> arg0) throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public <T> T unwrap(Class<T> arg0) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public void abort(Executor arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void clearWarnings() throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void close() throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void commit() throws SQLException {
            SleepTools.ms(70);
        }
    
        @Override
        public Array createArrayOf(String arg0, Object[] arg1) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Blob createBlob() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Clob createClob() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public NClob createNClob() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public SQLXML createSQLXML() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Statement createStatement() throws SQLException {
            SleepTools.ms(1);
            return null;
        }
    
        @Override
        public Statement createStatement(int arg0, int arg1) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Statement createStatement(int arg0, int arg1, int arg2) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Struct createStruct(String arg0, Object[] arg1) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public boolean getAutoCommit() throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public String getCatalog() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Properties getClientInfo() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public String getClientInfo(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public int getHoldability() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public DatabaseMetaData getMetaData() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public int getNetworkTimeout() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public String getSchema() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public int getTransactionIsolation() throws SQLException {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public Map<String, Class<?>> getTypeMap() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public SQLWarning getWarnings() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public boolean isClosed() throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public boolean isReadOnly() throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public boolean isValid(int arg0) throws SQLException {
            // TODO Auto-generated method stub
            return false;
        }
    
        @Override
        public String nativeSQL(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public CallableStatement prepareCall(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public CallableStatement prepareCall(String arg0, int arg1, int arg2) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public CallableStatement prepareCall(String arg0, int arg1, int arg2, int arg3) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public PreparedStatement prepareStatement(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public PreparedStatement prepareStatement(String arg0, int arg1) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public PreparedStatement prepareStatement(String arg0, int[] arg1) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public PreparedStatement prepareStatement(String arg0, String[] arg1) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public PreparedStatement prepareStatement(String arg0, int arg1, int arg2) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public PreparedStatement prepareStatement(String arg0, int arg1, int arg2, int arg3) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public void releaseSavepoint(Savepoint arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void rollback() throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void rollback(Savepoint arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setAutoCommit(boolean arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setCatalog(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setClientInfo(Properties arg0) throws SQLClientInfoException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setClientInfo(String arg0, String arg1) throws SQLClientInfoException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setHoldability(int arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setNetworkTimeout(Executor arg0, int arg1) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setReadOnly(boolean arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public Savepoint setSavepoint() throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public Savepoint setSavepoint(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            return null;
        }
    
        @Override
        public void setSchema(String arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setTransactionIsolation(int arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void setTypeMap(Map<String, Class<?>> arg0) throws SQLException {
            // TODO Auto-generated method stub
            
        }
        
    }
    package com.xiangxue.ch1.pool;
    
    import java.sql.Connection;
    import java.util.LinkedList;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:实现一个数据库的连接池
     */
    public class DBPool {
        
        //数据库池的容器
        private static LinkedList<Connection> pool = new LinkedList<>();
        
        public DBPool(int initalSize) {
            if(initalSize>0) {
                for(int i=0;i<initalSize;i++) {
                    pool.addLast(SqlConnectImpl.fetchConnection());
                }
            }
        }
        
        //在mills时间内还拿不到数据库连接,返回一个null
        public Connection fetchConn(long mills) throws InterruptedException {
            synchronized (pool) {
                if (mills<0) {
                    while(pool.isEmpty()) {
                        pool.wait();
                    }
                    return pool.removeFirst();
                }else {
                    long overtime = System.currentTimeMillis()+mills;
                    long remain = mills;
                    while(pool.isEmpty()&&remain>0) {
                        pool.wait(remain);//注意:等待remain时间后,执行wait,wait会释放锁
                        remain = overtime - System.currentTimeMillis();
                    }
                    Connection result  = null;
                    if(!pool.isEmpty()) {
                        result = pool.removeFirst();
                    }
                    return result;
                }
            }
        }
        
        //放回数据库连接
        public void releaseConn(Connection conn) {
            if(conn!=null) {
                synchronized (pool) {
                    pool.addLast(conn);
                    pool.notifyAll();
                }
            }
        }
    
     
    }
    package com.xiangxue.ch1.pool;
    
    import java.sql.Connection;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     *@author Mark老师   享学课堂 https://enjoy.ke.qq.com 
     *
     *类说明:
     */
    public class DBPoolTest {
        static DBPool pool  = new DBPool(10);
        // 控制器:控制main线程将会等待所有Woker结束后才能继续执行
        static CountDownLatch end;
    
        public static void main(String[] args) throws Exception {
            // 线程数量
            int threadCount = 50;
            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 Worker(count, got, notGot), 
                        "worker_"+i);
                thread.start();
            }
            end.await();// main线程在此处等待
            System.out.println("总共尝试了: " + (threadCount * count));
            System.out.println("拿到连接的次数:  " + got);
            System.out.println("没能连接的次数: " + notGot);
        }
    
        static class Worker implements Runnable {
            int           count;
            AtomicInteger got;
            AtomicInteger notGot;
    
            public Worker(int count, AtomicInteger got,
                                   AtomicInteger notGot) {
                this.count = count;
                this.got = got;
                this.notGot = notGot;
            }
    
            public void run() {
                while (count > 0) {
                    try {
                        // 从线程池中获取连接,如果1000ms内无法获取到,将会返回null
                        // 分别统计连接获取的数量got和未获取到的数量notGot
                        Connection connection = pool.fetchConn(1000);
                        if (connection != null) {
                            try {
                                connection.createStatement();
                                connection.commit();
                            } finally {
                                pool.releaseConn(connection);
                                got.incrementAndGet();
                            }
                        } else {
                            notGot.incrementAndGet();
                            System.out.println(Thread.currentThread().getName()
                                    +"等待超时!");
                        }
                    } catch (Exception ex) {
                    } finally {
                        count--;
                    }
                }
                end.countDown();
            }
        }
    }

    join()方法

    面试点

    线程A,执行了线程Bjoin方法,线程A必须要等待B执行完成了以后,线程A才能继续自己的工作

    调用yield() sleep()wait()notify()等方法对锁有何影响? 

    面试点

    线程在执行yield()以后持有的锁是不释放的,Cpu也是会有可能选择当前线程进行执行。

    sleep()方法被调用以后,持有的锁是不释放的,休眠的时候CPU不会选择改线程进行执行。

    调用方法之前必须要持有锁调用了wait()方法以后,锁就会被释放,当wait方法返回的时候,线程会重新持有锁

    调用方法之前必须要持有锁,调用notify()方法本身不会释放锁的

    一般将notify,notifyall放在同步代码块的最后。
    /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/ public synchronized void changeKm(){ this.km = 101; notifyAll(); //其他的业务代码 这样写不合理 }
  • 相关阅读:
    解决ActiveX插件ZIndex属性无效问题
    XNA游戏开发之字符篇
    XNA游戏开发之滚动背景
    ExtJs之FormPanel篇
    独立Discuz头像编辑模块
    XNA游戏开发之2D游戏
    WPF系列之应用程序生命周期
    DiscuzX2.0在windows下的配置
    Silverlight之out of Browser模式
    使用VisualStudio2010连接CodePlex进行代码管理
  • 原文地址:https://www.cnblogs.com/zqLoveSym/p/12245009.html
Copyright © 2020-2023  润新知