zoukankan      html  css  js  c++  java
  • 多线程 程序

    wait()和notify()示例

    public class Client{
        public static void main(String[] args) {
            Threada t1 = new Threada("t1");
            synchronized (t1) {
                try {
                    System.out.println(Thread.currentThread().getName() + "start t1");
                    t1.start();
                    System.out.println(Thread.currentThread().getName() + "wait");
                    t1.wait();
                    
                    System.out.println(Thread.currentThread().getName() + "continue");
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    }
    
    class Threada extends Thread {
        public Threada(String name) {
            super(name);
        }
        @Override
        public void run() {
            synchronized (this) {
                System.out.println(Thread.currentThread().getName() + "call notify");
                notify();
            }
        }
    }
    View Code
    mainstart t1
    mainwait
    t1call notify
    maincontinue
    View Code

    wait(long timeout)和notify()

    public class Client{
        public static void main(String[] args) {
            Threada t1 = new Threada("t1");
            synchronized (t1) {
                try {
                    System.out.println(Thread.currentThread().getName() + "start t1");
                    t1.start();
                    System.out.println(Thread.currentThread().getName() + "wait");
                    t1.wait(3000);
                    
                    System.out.println(Thread.currentThread().getName() + "continue");
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
        }
    }
    
    class Threada extends Thread {
        public Threada(String name) {
            super(name);
        }
        @Override
        public void run() {
            synchronized (this) {
                System.out.println(Thread.currentThread().getName() + "run");
                while (true) {
                    ;
                }
            }
        }
    }
    View Code
    main start t1
    main call wait 
    t1 run                  // 大约3秒之后...输出“main continue”
    main continue
    View Code

    wait() 和 notifyAll()

    public class Client{
        private static Object obj = new Object();
        public static void main(String[] args) {
            Threada t1 = new Threada("t1");
            Threada t2 = new Threada("t2");
            Threada t3 = new Threada("t3");
            t1.start();
            t2.start();
            t3.start();
            try {
                System.out.println(Thread.currentThread().getName() + "  sleep");
                Thread.sleep(3000);
            } catch (Exception e) {
                // TODO: handle exception
            }
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + "  notify all");
                obj.notifyAll();
                }
            }
        }
        static class Threada extends Thread {
            public Threada(String name) {
                super(name);
            }
            @Override
            public void run() {
                synchronized (obj) {
                    
                    try {
                        System.out.println(Thread.currentThread().getName() + "  await");
                        obj.wait();
                        System.out.println(Thread.currentThread().getName() + "  continue");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    View Code
    main  sleep
    t3  await
    t1  await
    t2  await
    main  notify all
    t2  continue
    t1  continue
    t3  continue
    View Code

    yield() 线程让步   它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权;

    public class Client{
        private static Object obj = new Object();
        public static void main(String[] args) {
            Threada t1 = new Threada("t1");
            Threada t2 = new Threada("t2");
            t1.start();
            t2.start();
        }
    }
    class Threada extends Thread {
        public Threada(String name) {
            super(name);
        }
        @Override
        public synchronized void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "  " + i);
                if (i % 4 == 0) {
                    Thread.yield();
                }
            }
        }
    }
    View Code

    (01) wait()是让线程由“运行状态”进入到“等待(阻塞)状态”,而不yield()是让线程由“运行状态”进入到“就绪状态”。
    (02) wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁。

    sleep  让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行。

    wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态”。
    但是,wait()会释放对象的同步锁,而sleep()则不会释放锁。

    public class Client{
        private static Object obj = new Object();
        public static void main(String[] args) {
            Threada t1 = new Threada("t1");
            Threada t2 = new Threada("t2");
            t1.start();
            t2.start();
        }
        static class Threada extends Thread {
            public Threada(String name) {
                super(name);
            }
            @Override
            public  void run() {
                synchronized (obj) {
                    try {
                        for (int i = 0; i < 10; i++) {
                            System.out.println(Thread.currentThread().getName() + "  " + i);
                            if (i % 4 == 0) {
                                Thread.sleep(400);
                            }
                        }
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    View Code
    t1: 0
    t1: 1
    t1: 2
    t1: 3
    t1: 4
    t1: 5
    t1: 6
    t1: 7
    t1: 8
    t1: 9
    t2: 0
    t2: 1
    t2: 2
    t2: 3
    t2: 4
    t2: 5
    t2: 6
    t2: 7
    t2: 8
    t2: 9
    View Code

    join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。

    public class Father extends Thread {
        public void run() {
            Son s = new Son();
            s.start();
            s.join();
            ...
        }
    }
    // 子线程
    public class Son extends Thread {
        public void run() {
            ...
        }
    }
    View Code
    public class Client{
        private static Object obj = new Object();
        public static void main(String[] args) throws InterruptedException {
            Threada t1 = new Threada("t1");
            t1.start();
            t1.join();
            System.out.println(Thread.currentThread().getName() + "  final");
        }
        static class Threada extends Thread {
            public Threada(String name) {
                super(name);
            }
            @Override
            public  void run() {
            //    synchronized (obj) {
                    System.out.println(Thread.currentThread().getName() + "  start");
                    for (int i = 0; i < 1000000; i++) {
                        
                    }
                    System.out.println(Thread.currentThread().getName() + "  final");
                }
        //    }
        }
    }
    View Code
    t1  start
    t1  final
    main  final
    View Code

    interrupt()  interrupt()的作用是中断本线程。

    本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。
    如果本线程是处于阻塞状态:调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“中断状态”会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该“中断标记”会立即被清除为“false”,同时,会产生一个InterruptedException的异常。
    如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时;线程的中断标记会被设置为true,并且它会立即从选择操作中返回。
    如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”。
    中断一个“已终止的线程”不会产生任何操作。

    终止处于“阻塞状态”的线程

    @Override
    public void run() {
        try {
            while (true) {
                // 执行任务...
            }
        } catch (InterruptedException ie) {  
            // 由于产生InterruptedException异常,退出while(true)循环,线程终止!
        }
    }
    View Code

    在while(true)中不断的执行任务,当线程处于阻塞状态时,调用线程的interrupt()产生InterruptedException中断。中断的捕获在while(true)之外,这样就退出了while(true)循环!
    注意:对InterruptedException的捕获务一般放在while(true)循环体的外面,这样,在产生异常时就退出了while(true)循环。否则,InterruptedException在while(true)循环体之内,就需要额外的添加退出处理。

    终止处于“运行状态”的线程

    @Override
    public void run() {
        while (!isInterrupted()) {
            // 执行任务...
        }
    }
    View Code

    isInterrupted()是判断线程的中断标记是不是为true。当线程处于运行状态,并且我们需要终止它时;可以调用线程的interrupt()方法,使用线程的中断标记为true,即isInterrupted()会返回true。此时,就会退出while循环。
    注意:interrupt()并不会终止处于“运行状态”的线程!它会将线程的中断标记设为true。

    @Override
    public void run() {
        try {
            // 1. isInterrupted()保证,只要中断标记为true就终止线程。
            while (!isInterrupted()) {
                // 执行任务...
            }
        } catch (InterruptedException ie) {  
            // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
        }
    }
    View Code
    class MyThread extends Thread {
     3 
     4     private volatile boolean flag= true;
     5     public void stopTask() {
     6         flag = false;
     7     }
     8     
     9     public MyThread(String name) {
    10         super(name);
    11     }
    12 
    13     @Override
    14     public void run() {
    15         synchronized(this) {
    16             try {
    17                 int i=0;
    18                 while (flag) {
    19                     Thread.sleep(100); // 休眠100ms
    20                     i++;
    21                     System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);  
    22                 }
    23             } catch (InterruptedException ie) {  
    24                 System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");  
    25             }
    26         }  
    27     }
    28 }
    View Code
    每个线程都有一个优先级。“高优先级线程”会优先于“低优先级线程”执行。每个线程都可以被标记为一个守护进程或非守护进程。在一些运行的主线程中创建新的子线程时,子线程的优先级被设置为等于“创建它的主线程的优先级”,当且仅当“创建它的主线程是守护线程”时“子线程才会是守护线程”。
    
    当Java虚拟机启动时,通常有一个单一的非守护线程(该线程通过是通过main()方法启动)。JVM会一直运行直到下面的任意一个条件发生,JVM就会终止运行:
    (01) 调用了exit()方法,并且exit()有权限被正常执行。
    (02) 所有的“非守护线程”都死了(即JVM中仅仅只有“守护线程”)。
    
    每一个线程都被标记为“守护线程”或“用户线程”。当只有守护线程运行时,JVM会自动退出。
    java 中有两种线程:用户线程守护线程。可以通过isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。java 中有两种线程:用户线程守护线程。可以通过isDaemon()方法来区别它们:如果返回false,则说明该线程是“用户线程”;否则就是“守护线程”。

    生产/消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”、“消费者”、“仓库”和“产品”。他们之间的关系如下:
    (01) 生产者仅仅在仓储未满时候生产,仓满则停止生产。
    (02) 消费者仅仅在仓储有产品时候才能消费,仓空则等待。
    (03) 当消费者发现仓储没产品可消费时候会通知生产者生产。
    (04) 生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

    复制代码
    
      1 // Demo1.java
      2 // 仓库
      3 class Depot {
      4     private int capacity;    // 仓库的容量
      5     private int size;        // 仓库的实际数量
      6 
      7     public Depot(int capacity) {
      8         this.capacity = capacity;
      9         this.size = 0;
     10     }
     11 
     12     public synchronized void produce(int val) {
     13         try {
     14              // left 表示“想要生产的数量”(有可能生产量太多,需多此生产)
     15             int left = val;
     16             while (left > 0) {
     17                 // 库存已满时,等待“消费者”消费产品。
     18                 while (size >= capacity)
     19                     wait();
     20                 // 获取“实际生产的数量”(即库存中新增的数量)
     21                 // 如果“库存”+“想要生产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满仓库)
     22                 // 否则“实际增量”=“想要生产的数量”
     23                 int inc = (size+left)>capacity ? (capacity-size) : left;
     24                 size += inc;
     25                 left -= inc;
     26                 System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d
    ", 
     27                         Thread.currentThread().getName(), val, left, inc, size);
     28                 // 通知“消费者”可以消费了。
     29                 notifyAll();
     30             }
     31         } catch (InterruptedException e) {
     32         }
     33     } 
     34 
     35     public synchronized void consume(int val) {
     36         try {
     37             // left 表示“客户要消费数量”(有可能消费量太大,库存不够,需多此消费)
     38             int left = val;
     39             while (left > 0) {
     40                 // 库存为0时,等待“生产者”生产产品。
     41                 while (size <= 0)
     42                     wait();
     43                 // 获取“实际消费的数量”(即库存中实际减少的数量)
     44                 // 如果“库存”<“客户要消费的数量”,则“实际消费量”=“库存”;
     45                 // 否则,“实际消费量”=“客户要消费的数量”。
     46                 int dec = (size<left) ? size : left;
     47                 size -= dec;
     48                 left -= dec;
     49                 System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d
    ", 
     50                         Thread.currentThread().getName(), val, left, dec, size);
     51                 notifyAll();
     52             }
     53         } catch (InterruptedException e) {
     54         }
     55     }
     56 
     57     public String toString() {
     58         return "capacity:"+capacity+", actual size:"+size;
     59     }
     60 } 
     61 
     62 // 生产者
     63 class Producer {
     64     private Depot depot;
     65     
     66     public Producer(Depot depot) {
     67         this.depot = depot;
     68     }
     69 
     70     // 消费产品:新建一个线程向仓库中生产产品。
     71     public void produce(final int val) {
     72         new Thread() {
     73             public void run() {
     74                 depot.produce(val);
     75             }
     76         }.start();
     77     }
     78 }
     79 
     80 // 消费者
     81 class Customer {
     82     private Depot depot;
     83     
     84     public Customer(Depot depot) {
     85         this.depot = depot;
     86     }
     87 
     88     // 消费产品:新建一个线程从仓库中消费产品。
     89     public void consume(final int val) {
     90         new Thread() {
     91             public void run() {
     92                 depot.consume(val);
     93             }
     94         }.start();
     95     }
     96 }
     97 
     98 public class Demo1 {  
     99     public static void main(String[] args) {  
    100         Depot mDepot = new Depot(100);
    101         Producer mPro = new Producer(mDepot);
    102         Customer mCus = new Customer(mDepot);
    103 
    104         mPro.produce(60);
    105         mPro.produce(120);
    106         mCus.consume(90);
    107         mCus.consume(150);
    108         mPro.produce(110);
    109     }
    110 }
    View Code
    public class Client{
    }
    
    class Depot {
        private int size;
        private int capacty;
        private Lock lock;
        private Condition fullCondition;
        private Condition emptyCondition;
        public Depot(int capacty) {
            super();
            this.capacty = capacty;
            this.size = 0;
            this.lock = new ReentrantLock();
            this.fullCondition = lock.newCondition();
            this.emptyCondition = lock.newCondition();
        }
        
        public void produce(int val) {
            lock.lock();
            try {
                int left = val;
                while (left > 0) {
                    while (size >= capacty) {
                        fullCondition.await();
                        int inc = (size + left) > capacty ? capacty - size : left;
                        size += inc;
                        left -= inc;
                        System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d
    ", 
                             Thread.currentThread().getName(), val, left, inc, size);
                        emptyCondition.signal();
                    }
                }
            } catch (Exception e) {
                // TODO: handle exception
            } finally {
                lock.unlock();
            }
        }
        
        public  void consume(int val) {
            lock.lock();
            try {
                int left = val;
                while (left > 0) {
                    while (size <= 0) {
                        emptyCondition.await();
                        int dec = (size >= left) ? left : size;
                        size -= dec;
                        left -= dec;
                        System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d
    ", 
                                 Thread.currentThread().getName(), val, left, dec, size);
                        fullCondition.signal();
                    }
                }
            } catch (Exception e) {
                // TODO: handle exception
            }finally {
                lock.unlock();
            }
        }
    }
    
    class Producer {
        private Depot depot;
    
        public Producer(Depot depot) {
            super();
            this.depot = depot;
        }
        public void produce(final int val)  {
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    depot.produce(val);
                }
            }).start();
        }
    }
    
    class Consumer {
        private Depot depot;
    
        public Consumer(Depot depot) {
            super();
            this.depot = depot;
        }
        public void consume(final int val)  {
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    depot.consume(val);
                }
            }).start();
        }
    }
    View Code

    (01) Producer是“生产者”类,它与“仓库(depot)”关联。当调用“生产者”的produce()方法时,它会新建一个线程并向“仓库”中生产产品。
    (02) Customer是“消费者”类,它与“仓库(depot)”关联。当调用“消费者”的consume()方法时,它会新建一个线程并消费“仓库”中的产品。
    (03) Depot是“仓库”类,仓库中记录“仓库的容量(capacity)”以及“仓库中当前产品数目(size)”。
            “仓库”类的生产方法produce()和消费方法consume()方法都是synchronized方法,进入synchronized方法体,意味着这个线程获取到了该“仓库”对象的同步锁。这也就是说,同一时间,生产者和消费者线程只能有一个能运行。通过同步锁,实现了对“残酷”的互斥访问。
           对于生产方法produce()而言:当仓库满时,生产者线程等待,需要等待消费者消费产品之后,生产线程才能生产;生产者线程生产完产品之后,会通过notifyAll()唤醒同步锁上的所有线程,包括“消费者线程”,即我们所说的“通知消费者进行消费”。
          对于消费方法consume()而言:当仓库为空时,消费者线程等待,需要等待生产者生产产品之后,消费者线程才能消费;消费者线程消费完产品之后,会通过notifyAll()唤醒同步锁上的所有线程,包括“生产者线程”,即我们所说的“通知生产者进行生产”。

  • 相关阅读:
    android29
    android28
    android27
    android26
    Dynamics CRM2011 MspInstallAction failed when installing an Update Rollup
    Dynamics CRM Import Solution Attribute Display Name description is null or empty
    The service cannot be activated because it does not support ASP.NET compatibility
    IIS部署WCF报 无法读取配置节“protocolMapping”,因为它缺少节声明
    Unable to access the IIS metabase.You do not have sufficient privilege
    LM算法与非线性最小二乘问题
  • 原文地址:https://www.cnblogs.com/whesuanfa/p/7495382.html
Copyright © 2011-2022 走看看