• java 线程(二)


    1. 描述下并行和并发的区别。

      并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,

          再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

      并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,

          两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

      区别:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。

    举个例子:

      你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
      你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。  (不一定是同时的)
      你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。  
     
    2.描述下线程的生命周期

    Java线程具有五中基本状态

    新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

    就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

    运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

    阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。

      根据阻塞产生的原因不同,阻塞状态又可以分为三种:

        1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

        2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

        3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

     3.线程中的 等待 和 通知 机制

        1.  调用wait()方法之后,当前线程进入休眠状态  并  释放锁

        2.  notify()  方法任意从 WAITTING 状态的线程中挑选一个进行通知(唤醒),使得调用wait()的方法的线程从等待队列移入到同步队列中,等待有机会再一次获取到锁,

          调用通知后,当前线程不会马上释放该对象锁,要等到程序退出同步块后,当前线程才会释放锁。

          notifyAll使所有原来在该对象上等待的线程统统退出WAITTING状态。

    注意:   1.  如果调用wait()和 notify()  方法之前,线程必须要获得该对象的对象监视器锁,则会抛出IllegalMonitorStateException异常。

                  2.   实例化一个lock , 使用wait和notify的时候一定要配合synchronized关键字去使用 ,这都验证了 wait()和 notify()  方法 只能在同步方法或同步块中调用。

        3. Condition的作用是对锁进行更精确的控制。

         Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。

           不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的;而Condition是需要与"互斥锁"/"共享锁"捆绑使用的。

    参考:http://www.cnblogs.com/skywang12345/p/3496716.html

    下面案例是:生产者和消费者模式

    package cm.生产者和消费者模式;
    /*  资源类(资源池)
     * 1.当消费者消费的资源不够时,通知生产者生产,消费者处于等待状态
     * 2.当生产者生产的资源饱和时,通知消费者消费,生产者处于等待状态
     */
    public class Resource {
        private int num;  //表示当前资源量
        private int size = 20;//表示资源池的大小(饱和状态)
    //表示消费了一个资源
        public synchronized void remove(){
            if(num>0){
                num--;
                System.out.println(Thread.currentThread().getName()+"消费了一件资源,剩余"+num+"件");
            this.notify(); }
    else{ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void add(){ if(num<size){ num++; System.out.println(Thread.currentThread().getName()+"生产了一件资源,剩余"+num+"件"); this.notify();//通知消费者消费 }else{ try { this.wait();//当资源的数量处于饱和状态生产者处于等待状态 } catch (InterruptedException e) { e.printStackTrace(); } } } }
    package cm.生产者和消费者模式;
    
    public class CustomerRunnable implements Runnable {
        Resource res;
        public CustomerRunnable(Resource res){
            this.res =  res;
        }
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                res.remove();
            }
        }
    }
    
    
    package cm.生产者和消费者模式;
    
    public class ProducerRunnable implements Runnable{
        Resource res;
        public ProducerRunnable(Resource res){
            this.res =  res;
        }
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                res.add();//表示让生产者生产
            }
            
        }
    }
    package cm.生产者和消费者模式;
    
    public class Test {
    
        public static void main(String[] args) {
            Resource res  = new Resource();//创建资源类
            ProducerRunnable pr  = new ProducerRunnable(res);//生产者
            CustomerRunnable cr = new  CustomerRunnable(res);//消费者
            Thread pr1 = new Thread(pr,"生产者A");//生产者线程
            Thread pr2 = new Thread(pr,"生产者B");
            
            Thread cr1 = new Thread(cr,"消费者1号");//消费者线程
            Thread cr2 = new Thread(cr,"消费者2号");
            
            pr1.start();
            pr2.start();
            cr1.start();
            cr2.start();
        }
    
    }

    下面案例是使用 juc锁 condition 来解决存钱和取钱案例

    package cm.await_signal_lock;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Account {
        private double money;//银行账户余额
        private ReentrantLock lock = new ReentrantLock();
        Condition con1 = lock.newCondition();
        
        public double getMoney() {
            return money;
        }
        public void setMoney(double money) {
            this.money = money;
        }
        public void saveMoney(double money){
                lock.lock();
                if(this.money > 0){
                    try {
                        con1.await();//通知存钱线程处于等待状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    this.money+=money;
                    System.out.println("存钱:"+money);
                }
                
                con1.signal();//通知等待的取钱线程进行取钱
                lock.unlock();        
        }
        public  void fetchMoney(double money){
            lock.lock();
                if(this.money > 0){
                    this.money-=money;
                    System.out.println("取钱"+money);
                    con1.signal();//通知等待的存钱线程进行存钱
                }
                try {
                    con1.await();//当账户没钱了,让取钱线程处于等待状态
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            lock.unlock();    
        }
    }
    public class FetchMoneyRunnable implements Runnable{
        
        Account acc;//银行账户对象
        public FetchMoneyRunnable(Account acc) {
            this.acc = acc;
        }
        
    //模拟账户取钱10次    
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                acc.fetchMoney(500);//取钱操作
            }        
        }
    }
    
    
    
    public class SaveMoneyRunnable implements Runnable{
        
        Account acc;
        public SaveMoneyRunnable(Account acc) {
            this.acc = acc;
        }
    
    // 模拟存钱10次
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                acc.saveMoney(1000);
            }
        }
    }
    public class Test {
        public static void main(String[] args) {
            Account acc = new Account();//创建一个账户
            FetchMoneyRunnable fmr = new FetchMoneyRunnable(acc);
            SaveMoneyRunnable smr = new SaveMoneyRunnable(acc);
            Thread fetch = new Thread(fmr);//取钱线程
            Thread save = new Thread(smr);//存钱线程
            
            //启动线程
            fetch.start();
            save.start();
        }
    }


  • 相关阅读:
    一张大图看懂Mvc启动过程
    NopCommerce 3. Controller 分析
    NopCommerce 1. NopCommerce Application_Start启动过程
    sublime addons backup
    vs2012中使用localdb实例还原一个sql server 2008r2版本的数据库
    使用TestNG进行浏览器(IE、Chrome、FireFox)并发兼容性测试
    Selenium调用IE时报“The path to the driver executable must be set by the webdriver.ie.driver system property”
    启动带有用户配置信息的FireFox浏览器
    Selenium_Chrome浏览器调用
    Selenium_IE11_FireFox调用实例
  • 原文地址:https://www.cnblogs.com/gshao/p/10099448.html
Copyright © 2020-2023  润新知