精华内容
下载资源
问答
  • 程序中的所有事物,在任意时刻只能执行步骤. 并发的多面性 并发解决的问题大体上可以分为"速度"和"设计可管理性"并发通常是提高运行在单处理器上的程序的性能. 实现并发最直接的方式是在操作系统...

     

    程序中的所有事物,在任意时刻都只能执行一个步骤.

     

    并发的多面性

    并发解决的问题大体上可以分为"速度"和"设计可管理性"两种

    并发通常是提高运行在单处理器上的程序的性能.

    实现并发最直接的方式是在操作系统级别使用进程.

     

    困难: 协调不同线程驱动的任务之间的对内存/IO 资源的使用. 以使得这些资源不会同时被多个任务访问.

     

    改进代码设计

    Java 的线程机制是抢占式,表示调度机制会周期性的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片,使得每个程序都会分配到数量合理的时间去驱动它的任务.

     

    基本的线程机制

    将程序划分为多个分离的/独立运行的任务.通过使用多线程机制,这些独立任务中的每一个都将由执行线程来驱动.

    一个线程就是在进程中的一个单一的顺序控制流,因此,单个进程可以拥有多个并发执行的任务.

    底层机制是切分 CPU 时间.

     

    定义任务

    线程可以驱动任务,因此你需要一种描述任务的方式,可以由 Runnable 接口来提供.

    Thead 类

    将 Runnable 对象转换为工作任务的传统方式就是把它交给一个 Thread 构造器.

    使用 Executor

    管理 Thread 对象.

    单个 Executor 被用来创建和管理系统中的所有任务

    shutdown () 方法的调用可以防止新的任务提交给Executor

     

    从任务中产生返回值

    Runnable 是执行工作的独立任务,但是它并不返回任何值.

    任务完成之时能够返回值: 实现 Callable 接口.

     

    Callabel 是一种具有参数类型的泛型,它的类型参数表示的事从方法 call()中返回值.

    并且必须使用 ExecutorService.submit()方法调用它.

     

    submit()方法会产生 Future 对象,他用 Callable 返回结果的特定类型进行了参数化.

     

    用 isDone() 方法,查看任务是否完成.

     

     

    package com.step21;
    
    
    import java.util.ArrayList;
    import java.util.concurrent.*;
    
    class TaskWithResult implements Callable<String>{
        private int id ;
        public TaskWithResult(int id){
            this.id = id ;
        }
    
        @Override
        public String call() throws Exception {
            return "result of TaskWithResult : "+id + " ,  currentThread : " + Thread.currentThread().getName();
        }
    }
    public class CallableDemo {
        public static void main(String[] args) throws Exception {
            ExecutorService exec = Executors.newCachedThreadPool();
            ArrayList<Future<String>> list = new ArrayList<>();
    
            for (int i = 0 ; i<10 ; i++) {
                list.add(exec.submit(new TaskWithResult(i))) ;
    
            }
    
            for (Future<String> fs : list) {
    
                System.out.println(fs.get());
    
            }
    
            exec.shutdown();
        }
    
    }
    
    
    output: 
    
    
    result of TaskWithResult : 0 ,  currentThread : pool-1-thread-1
    result of TaskWithResult : 1 ,  currentThread : pool-1-thread-2
    result of TaskWithResult : 2 ,  currentThread : pool-1-thread-3
    result of TaskWithResult : 3 ,  currentThread : pool-1-thread-3
    result of TaskWithResult : 4 ,  currentThread : pool-1-thread-1
    result of TaskWithResult : 5 ,  currentThread : pool-1-thread-3
    result of TaskWithResult : 6 ,  currentThread : pool-1-thread-3
    result of TaskWithResult : 7 ,  currentThread : pool-1-thread-1
    result of TaskWithResult : 8 ,  currentThread : pool-1-thread-1
    result of TaskWithResult : 9 ,  currentThread : pool-1-thread-3
    
    

     

    休眠

    sleep() 使任务终止执行指定的时间.

     

    优先级

    线程的优先级是将该线程的重要性传递给了调度器.

    尽管 CPU 处理现有线程集的顺序是不确定的,但是调度器将倾向于让优先权最高的线程先执行.

    然而,并不意味着优先权较低的线程将得不到执行.

    优先级较低的线程仅仅是执行的频率较低.

     

    在绝大多数的时间里,所有线程有应该以默认的优先级运行,试图操纵线程优先级通常是一种错误.

     

    让步 yield()

     

    后台线程

    程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分.因此,当所有的非后台线程结束时.程序也就终止了,同时会杀死进程中的所有后台线程. 反过来说,只要有任何非后台线程还在运行,程序就不会终止.

    必须在线程启动前调用 setDaemon()方法,才能把它设置为后台线程.

     

    编码的变体

    继承 Thread

     

    加入一个线程

    join() : 等待一段时间,直到第二个线程结束才继续执行.

     

     

    package com.step21;
    
    
    class Sleeper extends Thread{
        private int duration ;
        public Sleeper(String name , int sleepTime){
            super(name);
            this.duration = sleepTime;
            start();
        }
    
    
        public void run (){
            try {
                sleep(duration);
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "has awakened ... ");
        }
    }
    
    
    class Joiner extends Thread{
    
        private Sleeper sleeper ;
    
        public Joiner(String name , Sleeper sleeper){
            super(name);
            this.sleeper = sleeper;
            start();
        }
    
    
        public void run (){
            try {
                sleeper.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "join  completed ... ");
        }
    }
    
    
    public class Joining {
        public static void main(String[] args) {
            Sleeper sleepy = new Sleeper("Sleepy",1500) ;
            Sleeper grumpy = new Sleeper("Sleepy",1500);
    
            Joiner dopey = new Joiner("Dopey",sleepy) ;
    
            Joiner doc = new Joiner("Doc",sleepy) ;
    
            grumpy.interrupt();
    
        }
    
    }
    
    
    
    
    
    
    Connected to the target VM, address: '127.0.0.1:55371', transport: 'socket'
    java.lang.InterruptedException: sleep interrupted
    	at java.lang.Thread.sleep(Native Method)
    	at com.step21.Sleeper.run(Joining.java:15)
    Sleepyhas awakened ... 
    Sleepyhas awakened ... 
    Dopeyjoin  completed ... 
    Docjoin  completed ... 
    Disconnected from the target VM, address: '127.0.0.1:55371', transport: 'socket'
    
    

     

    创建有响应的用户界面.

     

    线程组

    线程组持有一个线程集合.

    "继续错误的代价由别人承担,承认错误的代价由自己承担"

     

    捕获异常

    由于线程的本质特性,使得你不能捕获从线程中逃逸的异常.

     

    package com.step21;
    
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadFactory;
    
    class ExceptionThread2 implements Runnable {
        public void run(){
            Thread t = Thread.currentThread();
    
            System.out.println(" run () by " + t);
    
            System.out.println(" eh = "+ t.getUncaughtExceptionHandler());
    
            throw new RuntimeException();
        }
    }
    
    class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
    
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("caught : " + e );
        }
    }
    
    class HandlerThreadFactory implements ThreadFactory{
        public Thread newThread(Runnable r){
    
            System.out.println(this+ " create new Thread .. ");
    
            Thread t = new Thread(r) ;
    
            System.out.println(" crreate " + t);
    
            t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler() );
    
            System.out.println(" eh = " + t.getUncaughtExceptionHandler() );
    
            return  t ;
        }
    }
    
    
    
    public class CaptureUncaughtException {
        public static void main(String[] args) {
            ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
    
            exec.execute(new ExceptionThread2());
    
        }
    
    }
    
    
    输出:
    
    Connected to the target VM, address: '127.0.0.1:55756', transport: 'socket'
    com.step21.HandlerThreadFactory@546a03af create new Thread .. 
     crreate Thread[Thread-0,5,main]
     eh = com.step21.MyUncaughtExceptionHandler@28864e92
     run () by Thread[Thread-0,5,main]
     eh = com.step21.MyUncaughtExceptionHandler@28864e92
    com.step21.HandlerThreadFactory@546a03af create new Thread .. 
     crreate Thread[Thread-1,5,main]
     eh = com.step21.MyUncaughtExceptionHandler@46d3a9
    caught : java.lang.RuntimeException
    Disconnected from the target VM, address: '127.0.0.1:55756', transport: 'socket'
    
    

     

     

     

    这个处理器只有在不存在线程专有的未捕获异常处理器的情况下才会被调用.

    系统会检查线程专有版本, 如果没有发现,则检查线程组是否有其专有的 UNcaughtException()方法

    如果也没有,在调用 defaultUncaughtExceptionHandler.

     

    共享受限资源

     

    不正确的访问资源

    方案: 序列化访问共享资源 - 给定时刻只允许一个任务访问共享资源.  - 互斥量


     

    synchronized void f(){ /*......*/}
    
    synchronized void g(){ /*......*/}
    
    
    
    

     

    所有对象都自动含有单一的锁.当在对象上调用其任意 synchronized 方法的时候,次对象都被加锁.这时该对象上的其他 synchronized 方法只有等到前一个方法调用完毕并释放了锁之后才能被调用.

    在使用并发时,将域设置为 private 是非常重要的,否则 synchronized 关键字就不能防止其他任务直接访问域,这样就会产生冲突.

    读写线程必须用相同的监视器锁同步

    每个访问临界共享资源的方法都必须被同步,否则他们就不能正确的工作.

     

    使用显式的 Lock 对象

    Lock 对象必须被显式地创建.锁定和释放.

    Lock() 必须放置在 finally 子句中带有 unlock 的 try-finally 的语句中.

     

    ReentrantLock允许你尝试着获取但最终未获得锁,如果其他人已经获取了锁,那么你就可以决定离开去做其他的事情了.而不是等待直至这个锁被释放.

     

    //: concurrency/AttemptLocking.java
    package concurrency; /* Added by Eclipse.py */
    // Locks in the concurrent library allow you
    // to give up on trying to acquire a lock.
    import java.util.concurrent.*;
    import java.util.concurrent.locks.*;
    
    public class AttemptLocking {
      private ReentrantLock lock = new ReentrantLock();
      public void untimed() {
        boolean captured = lock.tryLock();
        try {
          System.out.println("tryLock(): " + captured);
        } finally {
          if(captured)
            lock.unlock();
        }
      }
      public void timed() {
        boolean captured = false;
        try {
          captured = lock.tryLock(2, TimeUnit.SECONDS);
        } catch(InterruptedException e) {
          throw new RuntimeException(e);
        }
        try {
          System.out.println("tryLock(2, TimeUnit.SECONDS): " + captured);
        } finally {
          if(captured)
            lock.unlock();
        }
      }
      public static void main(String[] args) {
        final AttemptLocking al = new AttemptLocking();
        al.untimed(); // True -- lock is available
        al.timed();   // True -- lock is available
        // Now create a separate task to grab the lock:
        new Thread() {
          { setDaemon(true); }
          public void run() {
            al.lock.lock();
            System.out.println("acquired");
          }
        }.start();
        Thread.yield(); // Give the 2nd task a chance
        al.untimed(); // False -- lock grabbed by task
        al.timed();   // False -- lock grabbed by task
      }
    } 
    
    /* Output:
    tryLock(): true
    tryLock(2, TimeUnit.SECONDS): true
    acquired
    tryLock(): false
    tryLock(2, TimeUnit.SECONDS): false
    *///:~
    

     

     

    原子性与易变性

    原子操作时不能被线程调度机制中断的操作.

    一旦操作开始,那么它一定可以在可能发生的"上下文切换"之前(切换到其他线程)执行完毕.

     

    原子操作可由线程机制保证其不可中断.

     

    原子类

    AtomicInteger

    AtomicLong

    AtomicReference

     

    临界区

    防止多个线程同时访问方法内部的部分代码而不是防止访问整个方法. 通过这总方式分离出的代码段成为临界区.

    使用 synchronized 关键字建立.

     

     

     

    在其他对象上同步

     

    必须确保所有相关任务都是在同一个对象上同步.

     

    线程本地存储

    防止任务在共享资源上产生冲突的第二种方式就是根除对变量的共享.

    java.lang.ThreadLocal 类实现.

     

    ThreadLocal对象通常当做静态域存储.

     

    //: concurrency/ThreadLocalVariableHolder.java
    package concurrency; /* Added by Eclipse.py */
    // Automatically giving each thread its own storage.
    import java.util.concurrent.*;
    import java.util.*;
    
    class Accessor implements Runnable {
      private final int id;
      public Accessor(int idn) { id = idn; }
      public void run() {
        while(!Thread.currentThread().isInterrupted()) {
          ThreadLocalVariableHolder.increment();
          System.out.println(this);
          Thread.yield();
        }
      }
      public String toString() {
        return "#" + id + ": " +
          ThreadLocalVariableHolder.get();
      }
    }
    
    public class ThreadLocalVariableHolder {
      private static ThreadLocal<Integer> value =
        new ThreadLocal<Integer>() {
          private Random rand = new Random(47);
          protected synchronized Integer initialValue() {
            return rand.nextInt(10000);
          }
        };
      public static void increment() {
        value.set(value.get() + 1);
      }
      public static int get() { return value.get(); }
      public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i = 0; i < 5; i++)
          exec.execute(new Accessor(i));
        TimeUnit.SECONDS.sleep(3);  // Run for a while
        exec.shutdownNow();         // All Accessors will quit
      }
    } 
    
    /* Output: (Sample)
    #0: 9259
    #1: 556
    #2: 6694
    #3: 1862
    #4: 962
    #0: 9260
    #1: 557
    #2: 6695
    #3: 1863
    #4: 963
    ...
    *///:~
    


     

    终结任务

     

    装饰性花园

     

    //: concurrency/OrnamentalGarden.java
    package concurrency; /* Added by Eclipse.py */
    import java.util.concurrent.*;
    import java.util.*;
    import static net.mindview.util.Print.*;
    
    class Count {
      private int count = 0;
      private Random rand = new Random(47);
      // Remove the synchronized keyword to see counting fail:
      public synchronized int increment() {
        int temp = count;
        if(rand.nextBoolean()) // Yield half the time
          Thread.yield();
        return (count = ++temp);
      }
      public synchronized int value() { return count; }
    }
    
    class Entrance implements Runnable {
      private static Count count = new Count();
      private static List<Entrance> entrances =
        new ArrayList<Entrance>();
      private int number = 0;
      // Doesn't need synchronization to read:
      private final int id;
      private static volatile boolean canceled = false;
      // Atomic operation on a volatile field:
      public static void cancel() { canceled = true; }
      public Entrance(int id) {
        this.id = id;
        // Keep this task in a list. Also prevents
        // garbage collection of dead tasks:
        entrances.add(this);
      }
      public void run() {
        while(!canceled) {
          synchronized(this) {
            ++number;
          }
          print(this + " Total: " + count.increment());
          try {
            TimeUnit.MILLISECONDS.sleep(100);
          } catch(InterruptedException e) {
            print("sleep interrupted");
          }
        }
        print("Stopping " + this);
      }
      public synchronized int getValue() { return number; }
      public String toString() {
        return "Entrance " + id + ": " + getValue();
      }
      public static int getTotalCount() {
        return count.value();
      }
      public static int sumEntrances() {
        int sum = 0;
        for(Entrance entrance : entrances)
          sum += entrance.getValue();
        return sum;
      }
    }
    
    public class OrnamentalGarden {
      public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i = 0; i < 5; i++)
          exec.execute(new Entrance(i));
        // Run for a while, then stop and collect the data:
        TimeUnit.SECONDS.sleep(3);
        Entrance.cancel();
        exec.shutdown();
        if(!exec.awaitTermination(250, TimeUnit.MILLISECONDS))
          print("Some tasks were not terminated!");
        print("Total: " + Entrance.getTotalCount());
        print("Sum of Entrances: " + Entrance.sumEntrances());
      }
    }
    
    /* Output: (Sample)
    Entrance 0: 1 Total: 1
    Entrance 2: 1 Total: 3
    Entrance 1: 1 Total: 2
    Entrance 4: 1 Total: 5
    Entrance 3: 1 Total: 4
    Entrance 2: 2 Total: 6
    Entrance 4: 2 Total: 7
    Entrance 0: 2 Total: 8
    ...
    Entrance 3: 29 Total: 143
    Entrance 0: 29 Total: 144
    Entrance 4: 29 Total: 145
    Entrance 2: 30 Total: 147
    Entrance 1: 30 Total: 146
    Entrance 0: 30 Total: 149
    Entrance 3: 30 Total: 148
    Entrance 4: 30 Total: 150
    Stopping Entrance 2: 30
    Stopping Entrance 1: 30
    Stopping Entrance 0: 30
    Stopping Entrance 3: 30
    Stopping Entrance 4: 30
    Total: 150
    Sum of Entrances: 150
    *///:~
    

     

    在阻塞时总结

     

    线程状态:

    1. 新建
    2. 就绪
    3. 阻塞
    4. 死亡

     

    进入阻塞状态

    1. sleep 使任务进入休眠状态.任务在指定的时间不运行.
    2. wait 线程挂起. 直到接收到 notify消息 或 notifyAll() 消息.
    3. 任务在等待某个输入/输出完成.
    4. 任务试图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获得了这个锁.

    中断

     

    1.Runnable.run() 方法的中间打断, 设立标识,  清理资源

    2. Thread 类包含 interrupt() 方法.

    3. Executor  cancel(true)

     

    //: concurrency/Interrupting.java
    package concurrency; /* Added by Eclipse.py */
    // Interrupting a blocked thread.
    import java.util.concurrent.*;
    import java.io.*;
    import static net.mindview.util.Print.*;
    
    class SleepBlocked implements Runnable {
      public void run() {
        try {
          TimeUnit.SECONDS.sleep(100);
        } catch(InterruptedException e) {
          print("InterruptedException");
        }
        print("Exiting SleepBlocked.run()");
      }
    }
    
    class IOBlocked implements Runnable {
      private InputStream in;
      public IOBlocked(InputStream is) { in = is; }
      public void run() {
        try {
          print("Waiting for read():");
          in.read();
        } catch(IOException e) {
          if(Thread.currentThread().isInterrupted()) {
            print("Interrupted from blocked I/O");
          } else {
            throw new RuntimeException(e);
          }
        }
        print("Exiting IOBlocked.run()");
      }
    }
    
    class SynchronizedBlocked implements Runnable {
      public synchronized void f() {
        while(true) // Never releases lock
          Thread.yield();
      }
      public SynchronizedBlocked() {
        new Thread() {
          public void run() {
            f(); // Lock acquired by this thread
          }
        }.start();
      }
      public void run() {
        print("Trying to call f()");
        f();
        print("Exiting SynchronizedBlocked.run()");
      }
    }
    
    public class Interrupting {
      private static ExecutorService exec =
        Executors.newCachedThreadPool();
      
      static void test(Runnable r) throws InterruptedException{
        Future<?> f = exec.submit(r);
        TimeUnit.MILLISECONDS.sleep(100);
        
        print("Interrupting " + r.getClass().getName());
        f.cancel(true); // Interrupts if running
        print("Interrupt sent to " + r.getClass().getName());
        
      }
      
      public static void main(String[] args) throws Exception {
        test(new SleepBlocked());
        test(new IOBlocked(System.in));
        test(new SynchronizedBlocked());
    
        TimeUnit.SECONDS.sleep(3);
        
        print("Aborting with System.exit(0)");
        System.exit(0); // ... since last 2 interrupts failed
      }
    
    }
    /* Output: (95% match)
    Interrupting SleepBlocked
    InterruptedException
    Exiting SleepBlocked.run()
    Interrupt sent to SleepBlocked
    Waiting for read():
    Interrupting IOBlocked
    Interrupt sent to IOBlocked
    Trying to call f()
    Interrupting SynchronizedBlocked
    Interrupt sent to SynchronizedBlocked
    Aborting with System.exit(0)
    *///:~
    

     

    被互斥所阻塞

     

    //: concurrency/MultiLock.java
    package concurrency; /* Added by Eclipse.py */
    // One thread can reacquire the same lock.
    import static net.mindview.util.Print.*;
    
    public class MultiLock {
      public synchronized void f1(int count) {
        if(count-- > 0) {
          print("f1() calling f2() with count " + count);
          f2(count);
        }
      }
      public synchronized void f2(int count) {
        if(count-- > 0) {
          print("f2() calling f1() with count " + count);
          f1(count);
        }
      }
      public static void main(String[] args) throws Exception {
        final MultiLock multiLock = new MultiLock();
        new Thread() {
          public void run() {
            multiLock.f1(10);
          }
        }.start();
      }
    } 
    
    /* Output:
    f1() calling f2() with count 9
    f2() calling f1() with count 8
    f1() calling f2() with count 7
    f2() calling f1() with count 6
    f1() calling f2() with count 5
    f2() calling f1() with count 4
    f1() calling f2() with count 3
    f2() calling f1() with count 2
    f1() calling f2() with count 1
    f2() calling f1() with count 0
    *///:~
    

     

    检查中断

    interrupt()

    interrupted()

     

    //: concurrency/InterruptingIdiom.java
    package concurrency; /* Added by Eclipse.py */
    // General idiom for interrupting a task.
    // {Args: 1100}
    import java.util.concurrent.*;
    import static net.mindview.util.Print.*;
    
    class NeedsCleanup {
      private final int id;
      public NeedsCleanup(int ident) {
        id = ident;
        print("NeedsCleanup " + id);
      }
      public void cleanup() {
        print("Cleaning up " + id);
      }
    }
    
    class Blocked3 implements Runnable {
      private volatile double d = 1.0;
      public void run() {
        try {
          while(!Thread.interrupted()) {
            // point1
            NeedsCleanup n1 = new NeedsCleanup(1);
            // Start try-finally immediately after definition
            // of n1, to guarantee proper cleanup of n1:
            try {
              print("Sleeping");
              TimeUnit.SECONDS.sleep(1);
              // point2
              NeedsCleanup n2 = new NeedsCleanup(2);
              // Guarantee proper cleanup of n2:
              try {
                print("Calculating");
                // A time-consuming, non-blocking operation:
                for(int i = 1; i < 2500000; i++)
                  d = d + (Math.PI + Math.E) / d;
                System.out.println("d: " + d);
                print("Finished time-consuming operation");
              } finally {
                n2.cleanup();
              }
            } finally {
              n1.cleanup();
            }
          }
          print("Exiting via while() test");
        } catch(InterruptedException e) {
          print("Exiting via InterruptedException");
        }
      }
    }
    
    public class InterruptingIdiom {
      public static void main(String[] args) throws Exception {
        if(args.length != 1) {
          print("usage: java InterruptingIdiom delay-in-mS");
          System.exit(1);
        }
        Thread t = new Thread(new Blocked3());
        t.start();
        TimeUnit.MILLISECONDS.sleep(new Integer(args[0]));
        t.interrupt();
      }
    }
    
    /* Output: (Sample)
    NeedsCleanup 1
    Sleeping
    NeedsCleanup 2
    Calculating
    Finished time-consuming operation
    Cleaning up 2
    Cleaning up 1
    NeedsCleanup 1
    Sleeping
    Cleaning up 1
    Exiting via InterruptedException
    *///:~
    

     

    线程之间的协作

    使用线程来同时运行多个任务时,可以通过使用锁(互斥)来同步两个任务的行为.从而使得一个任务不会干涉另一个任务的资源.

     

    wait()和 notifyAll()

     

    wait(): 等待某个条件发生变化,而改变这个条件超出了当前方法的控制能力,释放锁 . 由 notify()或 notifyAll 唤醒.

    sheep(): 锁没有释放,yield() 也属于这种情况.

     

    当调用 wait()时,声明:"我已经刚刚做完能做的所有事情,因此我要在这里等待,但是我希望其他的 synchronized 操作在条件合适的情况下能够执行"

     

    对 wait()而言,与 sleep 有所区别.:

    1.在 wait()期间,对象锁是释放的.

    2.可以通过 notify() 或者 notifyAll() , 或者令时间到期,从 wait()中恢复执行.

     

     

    调用 wait() , nofify()和 notifyAll()的任务在调用这些方法前,必须"拥有"(获取)对象的锁?.

     

    //: concurrency/waxomatic/WaxOMatic.java
    // Basic task cooperation.
    package concurrency.waxomatic;
    import java.util.concurrent.*;
    import static net.mindview.util.Print.*;
    
    class Car {
      private boolean waxOn = false;
      public synchronized void waxed() {
        waxOn = true; // Ready to buff
        notifyAll();
      }
      public synchronized void buffed() {
        waxOn = false; // Ready for another coat of wax
        notifyAll();
      }
      public synchronized void waitForWaxing()
      throws InterruptedException {
        while(waxOn == false)
          wait();
      }
      public synchronized void waitForBuffing()
      throws InterruptedException {
        while(waxOn == true)
          wait();
      }
    }
    
    class WaxOn implements Runnable {
      private Car car;
      public WaxOn(Car c) { car = c; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            printnb("抛光   Wax On! ");
            TimeUnit.MILLISECONDS.sleep(500);
            car.waxed();
            car.waitForBuffing();
          }
        } catch(InterruptedException e) {
          print("Exiting via interrupt");
        }
        print("Ending Wax On task");
      }
    }
    
    class WaxOff implements Runnable {
      private Car car;
      public WaxOff(Car c) { car = c; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            car.waitForWaxing();
            printnb("打蜡   Wax Off! ");
            TimeUnit.MILLISECONDS.sleep(500);
            car.buffed();
          }
        } catch(InterruptedException e) {
          print("Exiting via interrupt");
        }
        print("Ending Wax Off task");
      }
    }
    
    public class WaxOMatic {
      public static void main(String[] args) throws Exception {
        Car car = new Car();
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new WaxOff(car));
        exec.execute(new WaxOn(car));
        TimeUnit.SECONDS.sleep(5); // Run for a while...
        exec.shutdownNow(); // Interrupt all tasks
      }
    }
    /* Output: (95% match)
    抛光   Wax On! 
    打蜡   Wax Off! 
    抛光   Wax On! 
    打蜡   Wax Off! 
    抛光   Wax On! 
    打蜡   Wax Off! 
    抛光   Wax On! 
    打蜡   Wax Off! 
    抛光   Wax On! 
    打蜡   Wax Off! 
    Exiting via interrupt
    Exiting via interrupt
    Ending Wax On task
    Ending Wax Off task
    *///:~
    

     

    当 notifyAll()因某个特定锁而被调用时,只有等待的这个锁的任务才被唤醒.

     

    生产者和消费者

     

    //: concurrency/Restaurant.java
    package concurrency; /* Added by Eclipse.py */
    // The producer-consumer approach to task cooperation.
    import java.util.concurrent.*;
    import static net.mindview.util.Print.*;
    
    class Meal {
      private final int orderNum;
      public Meal(int orderNum) { this.orderNum = orderNum; }
      public String toString() { return "Meal " + orderNum; }
    }
    
    class WaitPerson implements Runnable {
      private Restaurant restaurant;
      public WaitPerson(Restaurant r) { restaurant = r; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            synchronized(this) {
              while(restaurant.meal == null)
                wait(); // ... for the chef to produce a meal
            }
            print("Waitperson got " + restaurant.meal);
            synchronized(restaurant.chef) {
              restaurant.meal = null;
              restaurant.chef.notifyAll(); // Ready for another
            }
          }
        } catch(InterruptedException e) {
          print("WaitPerson interrupted");
        }
      }
    }
    
    class Chef implements Runnable {
      private Restaurant restaurant;
      private int count = 0;
      public Chef(Restaurant r) { restaurant = r; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            synchronized(this) {
              while(restaurant.meal != null)
                wait(); // ... for the meal to be taken
            }
            if(++count == 10) {
              print("Out of food, closing");
              restaurant.exec.shutdownNow();
            }
            printnb("Order up! ");
            synchronized(restaurant.waitPerson) {
              restaurant.meal = new Meal(count);
              restaurant.waitPerson.notifyAll();
            }
            TimeUnit.MILLISECONDS.sleep(100);
          }
        } catch(InterruptedException e) {
          print("Chef interrupted");
        }
      }
    }
    
    public class Restaurant {
      Meal meal;
      ExecutorService exec = Executors.newCachedThreadPool();
      WaitPerson waitPerson = new WaitPerson(this);
      Chef chef = new Chef(this);
      public Restaurant() {
        exec.execute(chef);
        exec.execute(waitPerson);
      }
      public static void main(String[] args) {
        new Restaurant();
      }
    }
    
    /* Output:
    Order up! Waitperson got Meal 1
    Order up! Waitperson got Meal 2
    Order up! Waitperson got Meal 3
    Order up! Waitperson got Meal 4
    Order up! Waitperson got Meal 5
    Order up! Waitperson got Meal 6
    Order up! Waitperson got Meal 7
    Order up! Waitperson got Meal 8
    Order up! Waitperson got Meal 9
    Out of food, closing
    WaitPerson interrupted
    Order up! Chef interrupted
    *///:~
    

     

    使用显示的 Lock 和 Condition 对象

     

    //: concurrency/waxomatic2/WaxOMatic2.java
    // Using Lock and Condition objects.
    package concurrency.waxomatic2;
    import java.util.concurrent.*;
    import java.util.concurrent.locks.*;
    import static net.mindview.util.Print.*;
    
    class Car {
      private Lock lock = new ReentrantLock();
      private Condition condition = lock.newCondition();
      private boolean waxOn = false;
      public void waxed() {
        lock.lock();
        try {
          waxOn = true; // Ready to buff
          condition.signalAll();
        } finally {
          lock.unlock();
        }
      }
      public void buffed() {
        lock.lock();
        try {
          waxOn = false; // Ready for another coat of wax
          condition.signalAll();
        } finally {
          lock.unlock();
        }
      }
      public void waitForWaxing() throws InterruptedException {
        lock.lock();
        try {
          while(waxOn == false)
            condition.await();
        } finally {
          lock.unlock();
        }
      }
      public void waitForBuffing() throws InterruptedException{
        lock.lock();
        try {
          while(waxOn == true)
            condition.await();
        } finally {
          lock.unlock();
        }
      }
    }
    
    class WaxOn implements Runnable {
      private Car car;
      public WaxOn(Car c) { car = c; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            printnb("Wax On! ");
            TimeUnit.MILLISECONDS.sleep(500);
            car.waxed();
            car.waitForBuffing();
          }
        } catch(InterruptedException e) {
          print("Exiting via interrupt");
        }
        print("Ending Wax On task");
      }
    }
    
    class WaxOff implements Runnable {
      private Car car;
      public WaxOff(Car c) { car = c; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            car.waitForWaxing();
            printnb("Wax Off! ");
            TimeUnit.MILLISECONDS.sleep(500);
            car.buffed();
          }
        } catch(InterruptedException e) {
          print("Exiting via interrupt");
        }
        print("Ending Wax Off task");
      }
    }
    
    public class WaxOMatic2 {
      public static void main(String[] args) throws Exception {
        Car car = new Car();
    
        ExecutorService exec = Executors.newCachedThreadPool();
    
        exec.execute(new WaxOff(car));
        exec.execute(new WaxOn(car));
    
        TimeUnit.SECONDS.sleep(3);
        exec.shutdownNow();
      }
    }
    /* Output: (90% match)
    Wax On! 
    Wax Off! 
    Wax On! 
    Wax Off! 
    Wax On! 
    Wax Off! 
    Exiting via interrupt
    Exiting via interrupt
    Ending Wax Off task
    Ending Wax On task
    Disconnected from the target VM, address: '127.0.0.1:58743', transport: 'socket'
    
    *///:~
    
    
    

     

    生产者-消费者与队列

     

     

    //: concurrency/ToastOMatic.java
    package concurrency; /* Added by Eclipse.py */
    // A toaster that uses queues.
    import java.util.concurrent.*;
    import java.util.*;
    import static net.mindview.util.Print.*;
    
    class Toast {
      public enum Status { DRY, BUTTERED, JAMMED }
      private Status status = Status.DRY;
      private final int id;
      public Toast(int idn) { id = idn; }
      public void butter() { status = Status.BUTTERED; }
      public void jam() { status = Status.JAMMED; }
      public Status getStatus() { return status; }
      public int getId() { return id; }
      public String toString() {
        return "Toast " + id + ": " + status;
      }
    }
    
    class ToastQueue extends LinkedBlockingQueue<Toast> {}
    
    class Toaster implements Runnable {
      private ToastQueue toastQueue;
      private int count = 0;
      private Random rand = new Random(47);
      public Toaster(ToastQueue tq) { toastQueue = tq; }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            TimeUnit.MILLISECONDS.sleep(
              100 + rand.nextInt(500));
            // Make toast
            Toast t = new Toast(count++);
            print(t);
            // Insert into queue
            toastQueue.put(t);
          }
        } catch(InterruptedException e) {
          print("Toaster interrupted");
        }
        print("Toaster off");
      }
    }
    
    // Apply butter to toast:
    class Butterer implements Runnable {
      private ToastQueue dryQueue, butteredQueue;
      public Butterer(ToastQueue dry, ToastQueue buttered) {
        dryQueue = dry;
        butteredQueue = buttered;
      }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            // Blocks until next piece of toast is available:
            Toast t = dryQueue.take();
            t.butter();
            print(t);
            butteredQueue.put(t);
          }
        } catch(InterruptedException e) {
          print("Butterer interrupted");
        }
        print("Butterer off");
      }
    }
    
    // Apply jam to buttered toast:
    class Jammer implements Runnable {
      private ToastQueue butteredQueue, finishedQueue;
      public Jammer(ToastQueue buttered, ToastQueue finished) {
        butteredQueue = buttered;
        finishedQueue = finished;
      }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            // Blocks until next piece of toast is available:
            Toast t = butteredQueue.take();
            t.jam();
            print(t);
            finishedQueue.put(t);
          }
        } catch(InterruptedException e) {
          print("Jammer interrupted");
        }
        print("Jammer off");
      }
    }
    
    // Consume the toast:
    class Eater implements Runnable {
      private ToastQueue finishedQueue;
      private int counter = 0;
      public Eater(ToastQueue finished) {
        finishedQueue = finished;
      }
      public void run() {
        try {
          while(!Thread.interrupted()) {
            // Blocks until next piece of toast is available:
            Toast t = finishedQueue.take();
            // Verify that the toast is coming in order,
            // and that all pieces are getting jammed:
            if(t.getId() != counter++ ||
               t.getStatus() != Toast.Status.JAMMED) {
              print(">>>> Error: " + t);
              System.exit(1);
            } else
              print("Chomp! " + t);
          }
        } catch(InterruptedException e) {
          print("Eater interrupted");
        }
        print("Eater off");
      }
    }
    
    public class ToastOMatic {
      public static void main(String[] args) throws Exception {
        ToastQueue dryQueue = new ToastQueue(),
                   butteredQueue = new ToastQueue(),
                   finishedQueue = new ToastQueue();
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new Toaster(dryQueue));
        exec.execute(new Butterer(dryQueue, butteredQueue));
        exec.execute(new Jammer(butteredQueue, finishedQueue));
        exec.execute(new Eater(finishedQueue));
        TimeUnit.SECONDS.sleep(2);
        exec.shutdownNow();
      }
    } /* (Execute to see output) *///:~
    

     

    任务间使用管道进行输出/输出

    //: concurrency/PipedIO.java
    package concurrency; /* Added by Eclipse.py */
    // Using pipes for inter-task I/O
    import java.util.concurrent.*;
    import java.io.*;
    import java.util.*;
    import static net.mindview.util.Print.*;
    
    class Sender implements Runnable {
      private Random rand = new Random(47);
      private PipedWriter out = new PipedWriter();
      public PipedWriter getPipedWriter() { return out; }
      public void run() {
        try {
          while(true)
            for(char c = 'A'; c <= 'z'; c++) {
              printnb("Sender: " + c + ", ");
              out.write(c);
              TimeUnit.MILLISECONDS.sleep(rand.nextInt(500));
            }
        } catch(IOException e) {
          print(e + " Sender write exception");
        } catch(InterruptedException e) {
          print(e + " Sender sleep interrupted");
        }
      }
    }
    
    class Receiver implements Runnable {
      private PipedReader in;
      public Receiver(Sender sender) throws IOException {
        in = new PipedReader(sender.getPipedWriter());
      }
      public void run() {
        try {
          while(true) {
            // Blocks until characters are there:
            printnb("Read: " + (char)in.read() + ", ");
          }
        } catch(IOException e) {
          print(e + " Receiver read exception");
        }
      }
    }
    
    public class PipedIO {
      public static void main(String[] args) throws Exception {
        Sender sender = new Sender();
        Receiver receiver = new Receiver(sender);
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(sender);
        exec.execute(receiver);
        TimeUnit.SECONDS.sleep(4);
        exec.shutdownNow();
      }
    } /* Output: (65% match)
    Read: A, Read: B, Read: C, Read: D, Read: E, Read: F, Read: G, Read: H, Read: I, Read: J, Read: K, Read: L, Read: M, java.lang.InterruptedException: sleep interrupted Sender sleep interrupted
    java.io.InterruptedIOException Receiver read exception
    *///:~
    

     

     

     

    尚未完成,节后整理.........

     

     

    680

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 操作系统之进程

    2014-09-07 16:23:21
    在多道程序环境下,程序可以并发执行,一程序的任意两条指令之间可能发生随机事件而引发程序切换。因而,每程序的执行可能不是连续的而是走走停停的。系统需要一能够描述程序动态执行的单位,于是就引入了...

    进程的引入

    在多道程序环境下,程序可以并发执行,一个程序的任意两条指令之间都可能发生随机事件而引发程序切换。因而,每个程序的执行都可能不是连续的而是走走停停的。系统需要一个能够描述程序动态执行的单位,于是就引入了进程。

    进程的生命周期

    同静态的程序相比较,进程依赖于处理器和主存储器资源, 具有动态性和暂时性。进程随着一个程序模块进入主存储器并获得一个数据块和一个进程 
    控制块而创建,因等待某个事件发生或资源得不到满足而暂停执行,随着运行的结束退出主存储器而消亡。

    “可再入”程序的概念

    所谓“可再入”程序是指能被多个程序同时调用的程序。另一种称“可再入”程序由于它被调用过程中具有自身修改,在调用它的程序退出以前是不允许其他程序来调用它的。

    进程的特点

    • 结构性:进程包含了数据集合和运行于其上的程序。为了描述和记录进程的动态变化过程使其能正确运行,还需配置一个进程控制块,所以每个进程至少有三要素组成:程序块、数据块和进程控制块。 
    • 共享性同一程序同时运行于不同数据集合上时,构成不同的进程。或者说多个不同的进程可以共享相同的程序,所以进程和程序不是一 一对的。
    • 动态性:进程是程序在数据集合上的一次执行过程,是动态概念。同时,它还有生命周期,由创建而产生,由调度而执行,由撤销而消亡。而程序是一组有序指令序列,是静态概念,所以,程序作为一种系统资源是永久存在的。 
    • 独立性:进程既是系统中资源分配和保护的基本单位,也是系统调度的独立单位(单线程进程)。凡是未建立进程的程序,都不能作为独立单位参与运行。通常,每个进程都可以各自独立的速度在CPU 上推进。 
    • 制约性:并发进程之间存在着制约关系,进程在进行的关键点上需要相互等待或互通消息,以保证程序执行的可再现性和计算结果的惟一性。 
    • 并发性:进程可以并发地执行,进程的并发性能改进资源利用率和提高系统效率。对于一个单处理器的系统来说,m个进程 P1,P2,P3…Pm, 是轮流占用处理器并发地执行。例 如,可能是这样进行的: P1进程执行了N1条指令后让出处理器给P2,P2执行了 N2条指令后让出处理器给 P3,…Pm执行了Nm 条指令后让出处理器给P1,…。因此,进程的执行是 可以被打断的,或者说,进程执行完一条指令后在执行下一条指令前,可能被迫让出处理器, 由其他若干个进程执行若干条指令后才能再次获得处理器而执行。

    进程的状态和转换

    1)三态模型
    • 运行(running )态:进程占有处理器正在运行。 
    • 就绪( ready)态:进程具备运行条件,等待系统分配处理器以便运行。 
    • 等待( wait)态:又称阻塞(blocked )态或睡眠(sleep )态,指进程不具备运行条件,正 在等待某个事件的完成。
    通常,一个进程在创建后将处于就绪状态。每个进程在执行过程中,任一时刻当且仅当 处于上述三种状态之一。


    2)五态模型
    相比三态模型,多了新建态(new)、终止态(exit)
    进程的创建:当操作系统为一个程序构造一 个进程控制块并分配地址空间之后,就创建了一个进程。


    3)七态模型
    由于进程的不断创建,系统的资源特别如内存资源已经不能满足进程运行的要求。这个时候就必须把某些进程挂起( suspend),对换到磁盘镜像区中(即从主内存中移出,换到辅存储器上),释放它所占有的某些资源,暂时不参与低级调度,起到平滑系统操作负荷的目的。

    一个挂起进程等同于不在主存的进程,因此,挂起的进程将不参与低级调度直到它们被对换进主存。

    挂起和等待的区别:挂起进程不在主存中,等待进程依然在主存中。

    相比五态模型,多了2种状态:
     挂起就绪态:进程具备运行条件,但目前在辅存储器上。只有当它对换到主存中才能被调度执行。
     挂起等待态:进程正在等待一个事件发生,且目前在辅存储器上。当事件发生结束,进程将变为挂起就绪态。



    进程控制块

    每一个进程都有一个也只有一个进程控制块,进程控制块是操作系统用于记录和刻画进程状态及有关信息的数据结构,也是操作系统掌握进程的惟一 资料结构,是操作系统控制和管理进程的主要依据。它包括了进程执行时的情况,以及进程让出处理器后所处的状态、断点等信息。

    进程控制块中有一种信息叫:现场信息
    用于保留一个进程在运行时存放在处理器现场中的各种信息,任何一个进程在让出处理器时必须把此时的处理器现场信息保存到进程控制块中,而当该进程重新恢复运行时就可以根据进程控制块中的现场信息来恢复处理器现场。



    展开全文
  • Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证: :事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作:事务中的...
  • 2020-12-13

    2020-12-13 19:15:14
    1.1并发:在同一个时间段内,可以执行两个或多个线程,但其执行过程有时间上的重叠(宏观上是同时,微观上仍是顺序执行)。 2.2并行:在同一个时间段内,多个进程在同一个时间点上同时执行,无论从微观还是宏观角度,...

    GIT学习

    1.并行开发流程描述
    2.git分布式版本控制原理
    3.Git Flow并行开发分支模型

    1. 并行和并发
      1.1并发:在同一个时间段内,可以执行两个或多个线程,但其执行过程有时间上的重叠(宏观上是同时,微观上仍是顺序执行)。
      2.2并行:在同一个时间段内,多个进程在同一个时间点上同时执行,无论从微观还是宏观角度,程序都是同时进行的。
      2.并行开发流程:
      在开发过程中关注主要技术活动和任务之间的并行性以及它们的相互关系,将密集型任务拆分成可以并行执行的若干个小块;
      每个小块的活动状态如下图, 在任意给定时间可能处于任意状态,一个活动的结束不会影其它活动。

    将小块进行合并,检查,测试,最后整合成最终项目。

    1. 分布式版本控制
      2.1集中式版本控制
      开发者之间的合作方式是共用一个仓库(repository),无论这个仓库是在本地还是在远端,只要是所有成员都共同存取同一个仓库,那么这种方式就是集中式(centralized)版本控制。

    2.2分布式版本控制
    简单的说,分布式的版本控制就是每个人都可以创建一个独立的代码仓库用于管理,各种版本控制的操作都可以在本地完成。每个人修改的代码都可以推送合并到另外一个代码仓库中。

    2.3分布式和集中式的区别

    在分布式版本控制系统中,每一个客户端都有一份完整的版本仓库,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。就算远程服务器宕机了磁盘损坏了,事后还是可以通过本地的镜像恢复远程服务器完整的版本信息。而集中式版本控制则做不到这一点,远程服务器磁盘损坏的结果就是以前提交的全部历史版本信息都会丢失,重新提交只会产生一个新的版本。一下是分布式版本控制系统的工作图:

    1. git flow并行开发分支模型
      3.1 Git Flow: Git Flow是构建在Git之上的一个组织软件开发活动的模型,是在Git之上构建的一项软件开发最佳实践。Git Flow是一套使用Git进行源代码管理时的一套行为规范和简化部分Git操作的工具。

    3.2 Git flow分支模型如下:

    上图从左往右看,分别为
    • 时间轴,从上往下时间在流逝
    • feature分支(玫红),图上有两个feature分支,在这个分支上,进行功能特性的开发
    • develop分支(黄色),git flow的主分支,feature分支和release分支都会将代码合并到此分支上
    • release分支(绿色),总是基于develop分支创建,最后合并到develop分支和master分支
    • hotfix分支(红色),总是基于master分支创建,最后合并到master分支和develop分支
    • master分支(蓝色),git flow的主分支,在开发的整个阶段一直存在,平时不在此分支开发,因此代码比较稳定,可以用来发布
    • Git Flow模型中定义了主分支和辅助分支两类分支。
    • 1、主分支用于组织与软件开发、部署相关的活动。
    • 主分支是所有开发活动的核心分支。所有的开发活动产生的输出物最终都会反映到主分支的代码中。
    • 主分支分为master分支和development分支。
    • 1). master分支
    • master分支上存放的应该是随时可供在生产环境中部署的代码(Production Ready state)。当开发活动告一段落,产生了一份新的可供部署的
    代码时,master分支上的代码会被更新。同时,每一次更新,最好添加对应的版本号标签(TAG)。
    • 2). develop分支
    • develop分支是保存当前最新开发成果的分支。通常这个分支上的代码也是可进行每日夜间发布的代码(Nightly build)。因此这个分支有时也可以被称作“integration branch”。
    • 当develop分支上的代码已实现了软件需求说明书中所有的功能,通过了所有的测试后,并且代码已经足够稳定时,就可以将所有的开发成果合并回master分支了。对于master分支上的新提交的代码建议都打上一个新的版本号标签(TAG),供后续代码跟踪使用。
    • 因此,每次将develop分支上的代码合并回master分支时,我们都可以认为一个新的可供在生产环境中部署的版本就产生了。通常而言,“仅在发布新的可供部署的代码时才更新master分支上的代码”是推荐所有人都遵守的行为准则。基于此,理论上说,每当有代码提交到master分支时,我们可以使用Git Hook触发软件自动测试以及生产环境代码的自动更新工作。这些自动化操作将有利于减少新代码发布之后的一些事务性工作。
    • 2、辅助分支组织为了解决特定的问题而进行的各种开发活动。
    • 辅助分支是用于组织解决特定问题的各种软件开发活动的分支。
    • 辅助分支主要用于组织软件新功能的并行开发、简化新功能开发代码的跟踪、辅助完成版本发布工作以及对生产代码的缺陷进行紧急修复工作。这些分支与主分支不同,通常只会在有限的时间范围内存在。
    • 辅助分支分为feature分支(开发新功能)、release分支(辅助版本发布)和hotfix分支(修正生产代码中的缺陷)。
    • 以上这些分支都有固定的使用目的和分支操作限制。从单纯技术的角度说,这些分支与Git其他分支并没有什么区别,但通过命名,我们定义了使用这些分支的方法。
    • 1). feature分支
    • 一般而言,feature分支代码可以保存在开发者自己的代码库中而不强制提交到主代码库里。
    • 使用规范:
    • (1).可以从develop分支发起feature分支
    • (2).代码必须合并回develop分支
    • (3).feature分支的命名可以使用除master,develop,release-,hotfix-之外的任何名称
    • (4).feature分支(有时也可以被叫做“topic分支”)通常是在开发一项新的软件功能的时候使用,这个分支上的代码变更最终合并回develop分支或者干脆被抛弃掉(例如实验性且效果不好的代码变更)。
    • 2). release分支
    • release分支是为发布新的产品版本而设计的。在这个分支上的代码允许做小的缺陷修正、准备发布版本所需的各项说明信息(版本号、发布时间、编译时间等等)。通过在release分支上进行这些工作可以让develop分支空闲出来以接受新的feature分支上的代码提交,进入新的软件开发迭代周期。
    • 当develop分支上的代码已经包含了所有即将发布的版本中所计划包含的软件功能,并且已通过所有测试时,我们就可以考虑准备创建release分支了。而所有在当前即将发布的版本之外的业务需求一定要确保不能混到release分支之内(避免由此引入一些不可控的系统缺陷)。
    • 成功的派生了release分支,并被赋予版本号之后,develop分支就可以为“下一个版本”服务了。所谓的“下一个版本”是在当前即将发布的版本之后发布的版本。版本号的命名可以依据项目定义的版本号命名规则进行。
    • 使用规范:
    • (1).可以从develop分支派生
    • (2).必须合并回develop分支和master分支
    • (3).分支命名惯例:release-*
    • 3). hotfix分支
    • 除了是计划外创建的以外,hotfix分支与release分支十分相似:都可以产生一个新的可供在生产环境部署的软件版本。
    • 当生产环境中的软件遇到了异常情况或者发现了严重到必须立即修复的软件缺陷的时候,就需要从master分支上指定的TAG版本派生hotfix分支来组织代码的紧急修复工作。
    • 这样做的显而易见的好处是不会打断正在进行的develop分支的开发工作,能够让团队中负责新功能开发的人与负责代码紧急修复的人并行的开展工作。

    参考博客:https://blog.csdn.net/qq_20097569/article/details/82660867

    展开全文
  • 针对这两个字段做唯一索引; 2.然后web服务器上直接插入,抓特定的Exception判断是不是违反了唯一性。 这个...我看行... <br/>问题补充</strong><br/><div class="quote_title">lixjluck 写道...
  • 例如,在Windows操作系统中,mp3播放进程和Word字处理进程可以并发执行,这样用户就可以边听音乐边写文章了。 (3) 处理机与设备之间的并行。例如,当处理机进行科学运算时,打印机可以打印文档。 (4) 处理机与通道...
  • 信号量(生产者和消费者模型)

    千次阅读 2017-04-30 20:08:15
    为了提高系统的并发性,我们引入了多进程,多线程,但是这样子带来了资源竞争,也就是多程序同时访问一共享资源而引发的一系列问题,因此我们需要协调多线程对与共享资源的访问,在任意时刻保证只能有一线程...

    信号量和管程都是操作系统用于同步提供的两种方法,我们将结合生产者与消费者模型对此进行学习。


    什么是信号量?

    为了提高系统的并发性,我们引入了多进程,多线程,但是这样子带来了资源竞争,也就是多个程序同时访问一个共享资源而引发的一系列问题,因此我们需要协调多线程对与共享资源的访问,在任意时刻保证只能有一个线程执行临界区代码。为了实现同步,我们可以利用底层硬件支持,也可以利用高层次的编程抽象,信号量和管程属于后者,是高层次的一种抽象,如下图:

    这里写图片描述

    信号量的定义:

    信号量(semaphore)是一种抽象数据类型,它是由一个(sem)整型变量(用于表示资源数目)和两个原子操作P,V组成。
    这两个操作分别是:

    P操作:在申请资源时候使用,将sem减1,如果sem小于0,就进入等待,否则直接使用资源即可,注意P操作有可能因为没有资源进入阻塞

    V操作:在释放资源时候使用,将sem加1,如果sem依旧小于等于0,说明之前有进程在等待使用这个资源,因此需要唤醒一个等待进程

    信号量的实现:

    由定义,我们给出信号量的伪代码实现:

    class Semaphore
    {
        //sem只能由P,V进行原子操作
        int sem;
        WaitQueue q;
        P()
        {
            sem--;
            if (sem < 0) //说明没有资源
            {
                //将线程t放入等待队列q中
                //阻塞
            }
        }
        Q()
        {
            sem++;
            if (sem <= 0)//说明有其他线程在等待使用该资源
            {
                //从等待队列中移除线程
                //唤醒
            }
        }
    }

    信号量的分类和使用:

    信号量可分为两种:

    二进制信号量:资源数目0或者1
    资源信号量:资源数目为任意非负值
    这两者等价,基于一个可以实现另一个

    信号量一般用于两种情况:

    互斥访问:临界区的互斥访问控制

    我们看一个例子,假设有一个共享资源,进程P0,P1对它进行操作,我们希望P0,P1都是互斥访问这个共享资源,那么我们该如何用信号量实现临界区的互斥访问?

    我们为此资源设置一个信号量,初值为1,mutx = New Semaphore(1)

    mutex->P();
    Critical Section;//临界区操作
    mutex->V();

    由于P0,P1访问顺序的不确定性,我们不妨让P0先访问(P1同理),P0执行mutex->P(),将资源mutex数目由1减为0(这一步是原子操作不可打断)

    此时,如果P1不行进行访问,那么P0会顺利执行临界区操作,如果P1进行访问,那么由于P0已经执行了对应的P操作让sem=0,P1自己在执行P操作过程中,sem减1等于-1,那么P1进程会阻塞自己,进入等待队列。

    直到P0访问完临界区,执行V操作,将mutex加1等于0,去唤醒P1进程,P1才会去访问共享资源。

    通过这样的一种机制,完成了对于临界区的互斥访问。

    条件同步:线程之间的时间等待

    同样的,我们举例说明,有两个进程A,B,他们会执行各自的指令

    这里写图片描述

    其中,线程A必须等线程B中X指令执行完才可以执行N指令,比如说X是接受数据,N是处理数据这样的操作等。。。

    为了实现这样的同步机制,我们条件设置一个信号量,其初值为0

    condition = New Semaphore(0)

    这里写图片描述

    由于A,B的执行次序不定,我们分类讨论。

    1. B先执行:B执行到V操作时候,将condition从0加为1,此时如果切换到A执行,那么A执行到P操作,发现condition-1为0,可以继续执行N指令
    2. A先执行:A执行到P操作时候,将condition从0减为-1,由于condition<0,则A会阻塞自己,接下来B执行到V操作,将condition从-1加到0,此时B知道有进程在等待资源,因此它去唤醒A,A因此执行了N指令

    通过这样的机制完成同步等待。

    生产者和消费者模型

    这里写图片描述

    这里写图片描述

    在上述图片中,将mutex信号量用于完成互斥访问,full,empty则用于完成问题分析中两个条件同步,因此我们将一个实际问题转化为信号量可以解决的问题

    这里写图片描述

    如上图,我们在类中定义了三个信号量用于完成互斥,同步操作,初始时候,mutex表示资源为1,full表示当前满缓冲区的个数为0,empty表示当前buffer都为空,(我们设定缓冲取的大小为n,因此full+empty == n)

    首先必须保证互斥操作,也就是任意时刻只有一个线程能操作缓冲区,要么是生产者,要么是消费者,因此我们在Deposit(生产者),Remove(消费者)中分别进行了PV操作。(具体过程和上面互斥访问一致,不清楚可以往前翻看)

    下面我们要来处理缓冲区满或者空时,条件同步是如何实现的?

    对于生产者,如果缓冲区满,则必须阻塞自己,只有等消费者消费了,缓冲区还有空缓冲区才能够继续生产,因此,我们需要同时改写Deposit(c)和Remove(c)的代码:

    Deposit(c)
    {
        empty->P();//检查是否还有空缓冲区
    
        mutex->P();
        Add c;
        mutex->V();
    }
    
    Remove(c)
    {
        mutex->P();
        Remove c;
        mutex->V();
    
        empty->V();//消费者读取一个数据,释放一个空缓冲区资源
    }
    

    同理对于消费者,如果缓冲区为空,则必须阻塞自己,只有等生产者生产了,缓冲区还有东西才能够继续消费,因此,我们也需要同时改写Deposit(c)和Remove(c)的代码:

    Deposit(c)
    {
        empty->P();//检查是否还有空缓冲区
    
        mutex->P();
        Add c;
        mutex->V();
    
        full->V();//生产者生成了数据,需要将满缓冲区个数加1
    }
    
    Remove(c)
    {
        full->P();//检查缓冲区里面是否还有东西,若缓冲区为空,则阻塞自己
    
        mutex->P();
        Remove c;
        mutex->V();
    
        empty->V();//消费者读取一个数据,释放一个空缓冲区资源
    }

    这里写图片描述

    展开全文
  • (两个进程间,线程ID允许相同) 注意:不应使用全局变量 pthread_t tid,在子线程中通过pthread_create传出参数来获取线程ID,而应使用pthread_self。 pthread_create函数 创建一个新线程。 其作用,对应进程中fork...
  • 并发执行依赖脚本,任意脚本出错或超时不会影响其他依赖脚本,但是会中断用户job 同步执行 同步执行依赖脚本,执行顺序为添加顺序,如果有一依赖脚本出错或超时,则会中断后继依赖,以及用户job 脚本异常...
  • 2.2.9 A,B,C,D四个进程,A向buf里面写数据,B,C,D向buf里面读数据,当A写完,且B,C,D读一次后,A才能再写。用P,V操作实现。 2.3.0 将单向链表reverse,如ABCD变成DCBA,只能搜索链表一次。 2.3.1 将二叉树的...
  • 答:服务器端向客户端发送一个进程编号,一个程序域编号,以确定对象的位置。 24.在C#中,string str = null 与 string str = “” 请尽量使用文字或图象说明其中的区别。 答:string str = null 是不给他分配...
  • 凌波多媒体教室6.6版

    2009-11-04 23:19:10
    双向对讲:指定某两个学生或者教师与某个学生之间,进行语音 交流,可同时设定多个双向对讲组 8. 多人会话:指定多个学生(可包括教师)之间进行语音交流,可同 时设定多个多人会话组 9. 网上讨论:指定多...
  • IIS6.0 IIS,互联网信息服务

    热门讨论 2010-08-23 21:20:55
    经过验证,WWW、FTP等几服务经过这样的修改都可以在Windows XP家庭版上正常运行。不过经过这样处理安装的IIS在运行上可能存在某种未知的缺陷。 四、在Vista系统中安装IIS7.0相对于早先的版本,IIS 7.0 带来了许多...
  • # 注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制, # 所以不要设置的太高. innodb_write_io_threads = 4 innodb_read_io_threads = 4 # innodb使用后台线程处理数据页上的读写 I/O(输入输出)请求,...
  • 凌波多媒体电子教室

    2012-06-25 11:26:41
    双向对讲:指定某两个学生或者教师与某个学生之间,进行语音交流; 多人会话:指定多个学生(可包括教师)之间进行语音交流; 声音监听:让教师或某个学生对某组或全体学生进行监听; 网络复读:利用现有音频、视频...
  • fourinone-3.04.25

    2013-12-11 21:35:04
    总的来说,是将大数据的复杂分布式计算,设计为一链式的多“包工头”环节去处理,每环节包括利用多台“农民工”机器进行并行计算,无论是拆分计算任务还是合并结果,都可以设计为一单独的“包工头”环节。...
  • FAQ(持续更新)

    2021-01-08 12:27:51
    两个队列将近倾向于同时执行完毕。这个规律可以扩展到任意队列数量以及任意启动顺序。 为什么使用redis client时无需先建立连接 首先看一下redis client任务的创建接口: ~~~cpp class WFTaskFactory { ...
  • Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将...
  • java开源包1

    千次下载 热门讨论 2013-06-28 09:14:34
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • java开源包12

    热门讨论 2013-06-28 10:14:45
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • Java资源包01

    2016-08-31 09:16:25
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • java开源包101

    2016-07-13 10:11:08
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • java开源包11

    热门讨论 2013-06-28 10:10:38
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • java开源包2

    热门讨论 2013-06-28 09:17:39
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • java开源包3

    热门讨论 2013-06-28 09:20:52
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...
  • java开源包6

    热门讨论 2013-06-28 09:48:32
    同时,任何第三方都可以使用OAUTH认证服务,任 何服务提供商都可以实现自身的OAUTH认证服务,因而OAUTH是开放的。业界提供了OAUTH的多种实现如PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间...

空空如也

空空如也

1 2 3
收藏数 49
精华内容 19
关键字:

任意两个进程都可以并发执行