zoukankan      html  css  js  c++  java
  • Java多线程基础(二)

      信号量Semaphore,类似于锁的功能,用于多线程中对一组资源的控制。

      acquire方法用于尝试获取一个资源,未获取前将一直等待。release用于释放一个资源,release的前提是已经获得了一个资源。 

    package multiThread;
    
    import java.util.concurrent.Semaphore;
    
    public class SemaphoreTest {
        public static void main(String [ ] args) {
            
            int N = 8; //工人数
            
            Semaphore semaphore = new Semaphore(5); //机器数目
            
            for (int i = 1; i < N; i++)
                
                new Worker(i, semaphore).start();
            
        }
        
        static class Worker extends Thread {
            
            private int num;
            
            private Semaphore semaphore;
            
            public Worker(int num, Semaphore semaphore) {
                
                this.num = num;
                
                this.semaphore = semaphore;
                
            }
            
            @Override
            public void run() {
                
                try {
                    
                    semaphore.acquire();
                    
                    System.out.println("工人" + this.num + "占用一个机器在生产...");
                    
                    Thread.sleep(2000);
                    
                    System.out.println("工人" + this.num + "释放出机器");
                    
                    semaphore.release();
                    
                }
                catch (InterruptedException e) {
                    
                    e.printStackTrace();
                    
                }
                
            }
            
        }
        
    }

      运行的结果为:

    工人1占用一个机器在生产...
    工人3占用一个机器在生产...
    工人2占用一个机器在生产...
    工人4占用一个机器在生产...
    工人5占用一个机器在生产...
    工人3释放出机器
    工人2释放出机器
    工人6占用一个机器在生产...
    工人4释放出机器
    工人1释放出机器
    工人5释放出机器
    工人7占用一个机器在生产...
    工人6释放出机器
    工人7释放出机器

      如果在获取资源的过程中不希望一直等待,也可以使用下面的方法判断是否能获取资源。

      tryAcquire(),尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false。

      tryAcquire(long timeout, TimeUnit unit),尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false。

     

       Thread的run方法是不抛出任何检查型异常(checked exception)的,但是它自身却可能因为一个异常而被终止,导致这个线程的终结。最麻烦的是,在线程中抛出的异常即使使用try...catch也无法截获,因此可能导致一些问题出现,比如异常的时候无法回收一些系统资源,或者没有关闭当前的连接等等。
      如果程序里面使用了多线程技术的话!就需要对子线程的异常做出特殊的处理,如果没有做特殊处理的话,好像子线程的异常不会抛给主线程,有时会直接在客户端抛出异常(这当然不是我们想要的),更夸张的是,有时直接把程序给强制关闭了!
      如下面的例子,即使main线程中加上了try-catch也无法捕获子线程抛出的异常:

    package multiThread.exception;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ExceptionThread implements Runnable{    
        
        @Override
        public void run() {
            throw new RuntimeException();
        }
        
    
        public static void main(String [ ] args) {
            try {
                ExecutorService exec = Executors.newCachedThreadPool();
                exec.execute(new ExceptionThread());
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }

      输出为:

    Exception in thread "pool-1-thread-1" java.lang.RuntimeException
        at multiThread.exception.ExceptionThread.run(ExceptionThread.java:10)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

      可以创建线程时绑定UncaughtExceptionHandler,UncaughtExceptionHandler的uncaughtException方法会在线程死亡前被调用。

    package multiThread.exception;
    
    import java.lang.Thread.UncaughtExceptionHandler;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ThreadFactory;
    
    class ExceptionThread2 implements Runnable{        
        @Override
        public void run() {
            System.out.println("eh = " + Thread.currentThread().getUncaughtExceptionHandler());
            throw new RuntimeException();
        }
    }
    
    class MyUncaughtExceptionHandler implements UncaughtExceptionHandler{
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println(t.getName() + " caught " + e);
        }    
    }
    
    class HandlerFactory implements ThreadFactory{
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
            return t;
        }
        
    }
    
    public class CaptureUncaughtException {
            
        public static void main(String [ ] args) {
            ExecutorService exec = Executors.newCachedThreadPool(new HandlerFactory());
            exec.execute(new ExceptionThread2());
        }    
    }

      输出结果为:

    eh = multiThread.exception.MyUncaughtExceptionHandler@3ec5bfc8
    Thread-0 caught java.lang.RuntimeException

      上面的例子是使用HandlerFactory为每一个线程加上了UncaughtExceptionHandler,也可以不使用HandlerFactory直接为线程加上UncaughtExceptionHandler。

     

     

      

      

  • 相关阅读:
    Aurora 数据库支持多达五个跨区域只读副本
    Amazon RDS 的 Oracle 只读副本
    Amazon EC2 密钥对
    DynamoDB 读取请求单位和写入请求单位
    使用 EBS 优化的实例或 10 Gb 网络实例
    启动 LAMP 堆栈 Web 应用程序
    AWS 中的错误重试和指数退避 Error Retries and Exponential Backoff in AWS
    使用 Amazon S3 阻止公有访问
    路由表 Router Table
    使用MySQLAdmin工具查看QPS
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/4567720.html
Copyright © 2011-2022 走看看