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

    创建任务和线程

      1,任务类实现implements接口,重写run方法;

    public class TaskClass implements Runnable{
      public TaskClass(){
           // ...
        }
         public void run(){
        //...
        } 
    }

      2, 使用Thread创建线程,Thread类包括创建线程的构造方法以及控制线程的方法;

    TaskClass task new TaskClass();//创建任务
    Thread thread = new Thread(task);//为任务创建线程

    Thread类的方法  

    Thread()                             //创建一个空线程 
    Thread(Runnable task)     //为指定任务创建一个线程
    void start()                         //启动线程,使得run()方法被调用
    boolean isAlive(int p)        //j检测线程当前是否在运行
    void setPriority()               //设置线程的优先级p (范围从1到10)
    void join()                          //等到线程结束     例如:A线程调用B.join(),则A线程进入阻塞队列,等B线程运行完后,唤醒A线程
    void sleep(long millis)      //使线程睡眠指定毫秒
    void yield()                      //当前线程暂停,进入就绪队列,运行其他线程

    线程池

    通过Thread来创建线程对单一任务的执行很方便,但需要为每个任务创建一个线程,对应大量任务来说是不够搞效的。因此java提供Executor接口来执行线程池中的任务,提供ExecutorService接口来管理和控制任务。

    1,使用Executors类中的静态方法创建Executor对象

    newFixedThreadPool(int)//创建固定数目的线程,当线程完成了任务的执行,它可以被重新使用以执行另外一个任务。当所有线程都不是空闲状态,而且有任务在等待,那么在关机前,如果因为错误终止了一个线程,就会创建一个新线程代替它。

    newCachedThreadPool()//当有线程在等待时就创建新的线程,缓冲池中的线程的线程60秒没有使用就终止它。

    Executor类的方法

    execute(Runnable object)//接受任务
     
    ExecutorService接口的方法
    void shutdown()  //关闭执行器,不接受新的任务,但要运行完已有的任务
    list<Runnable> shutdownNow()   //关闭执行器,即使还有任务没完成任务,返回没完成的任务清单
    boolean isShutdown()    //检测执行器是够已关闭
    boolean isTerminated()    //如果线程池所有任务都被终止,则返回true
     1 import java.util.concurrent.*;
     2 
     3 class PrintChar implements Runnable{
     4     char c;
     5     int len;
     6     public PrintChar(char a,int length) {
     7         c=a;
     8         len=length;
     9     }
    10     @Override
    11     public void run() {
    12         // TODO 自动生成的方法存根
    13         for(int i=0;i<len;i++) {
    14             System.out.print(c);
    15         }
    16     }
    17     
    18 }
    19 
    20 public class ExecutorDemo {
    21     public static void main(String args[]) {
    22 //        ExecutorService executor = Executors.newFixedThreadPool(1);
    23         ExecutorService executor = Executors.newCachedThreadPool();
    24         executor.execute(new PrintChar('a',100));
    25         executor.execute(new PrintChar('b',100));
    26         executor.execute(new PrintChar('c',100));
    27         
    28         executor.shutdown();
    29     }
    30 }
    View Code

    线程同步

     synchronized 同步的方法在执行前会隐式的加上一个锁:方法锁,对象锁 和 类锁

    1,给方法加synchronized关键字

      1)给普通方法加:当运行到这个方法时,实际是给调用这个方法的对象加锁,其他线程调用这个对象的这个方法时就会阻塞;

      2)给静态方法加:当运行到这个方法时,实际是给调用这个方法的类加锁,其他线程调用这个类的这个方法时就会阻塞;

    public synchronized void deposit(double amount)//当运行到这里调用这个方法的时候,实际上是给调用这个方法的对象加锁了
    public synchronized static void deposit(double amount)//当运行到这里调用这个方法的时候,实际上是给这个方法的类加锁了

    2, 给同步块加锁:可以给任何对象加锁,只会同步部分代码,而不必同步整个方法,大大增强了程序的并发能力;

      1)对调用这个方法的对象加锁

    public void acount(){
      synchronized (this){//还可写其他对象的名字,表示对其他对象加锁
           ...... 
        }      
    }

      2)给这个方法的类加锁

    public void acount(){
      synchronized (acount.class){//方法.class  可以给这个方法的所属类加锁
           ...... 
        }      
    }

    java显式的加锁:显式加锁对线程的控制更加直观灵活,重要的是可以进行线程间的协作

     通过ReentrantLock类可以实现接口Lock来表示一个锁,ReentrantLock是创建相互排斥的锁的Lock的具体表现。

    创建Lock锁,获取锁,释放锁

    Lock lock =new ReentrantLock();//创建锁
    lock.lock();//获取锁
    lock.unlock();//释放锁

    线程间协作

    调用Lock对象的newCondition()方法创建的对象可以使用await(),signal(),signalAll()方法来实现线程之间的互相通信。

    Lock lock = new ReentrantLock();
    Condition newDeposit = lock.newCondition();
    newDeposit.await();//当前线程等待,直到被signal()或signalAll()唤醒
    newDeposit.signal();//唤醒一个等待线程
    newDeposit.signalAll();//唤醒所以等待线程

    示例学习:生产者/消费者

    package test;
    import java.util.concurrent.*;
    import java.util.concurrent.locks.*;
    
    public class ConsumerProducer {
        public static Buffer buffer=new Buffer();
        public static void main(String args[]) {
            ExecutorService executor = Executors.newFixedThreadPool(2);
            executor.execute(new ProducerTack());
            executor.execute(new ConsumerTask());
            executor.shutdown();
        }
        private static class ProducerTack implements Runnable{
            public ProducerTack() {
                // TODO 自动生成的构造函数存根
            }
    
            @Override
            public void run() {
                try {
                    int i=1;
                    while(true) {
                        System.out.println("Producer writes" + i);
                        buffer.write(i++);
                        Thread.sleep((int)(Math.random()*10000));
                    }
                }catch(InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
            
        }
    
        private static class ConsumerTask implements Runnable{
            public ConsumerTask() {
                // TODO 自动生成的构造函数存根
            }
    
            public void run() {
                try {
                    while(true) {
                        System.out.println("			Consumer reads " + buffer.read());
                        Thread.sleep((int)(Math.random()*10000));
                    }
                }catch(InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    
        
        private static class Buffer{
            private static final int CAPACITY=1;
            private java.util.LinkedList<Integer> queue=new java.util.LinkedList<Integer>();
            
            private static Lock lock=new ReentrantLock();
            private static Condition notEmpty=lock.newCondition();
            private static Condition notFull = lock.newCondition();
            
            public Buffer() {
                // TODO 自动生成的构造函数存根
            }
    
            public void write(int value) {
                lock.lock();
                try {
                    while(queue.size()==CAPACITY) {
                        System.out.println("Wait for notFull condition");
                        notFull.await();
                    }
                    queue.offer(value);
                    notEmpty.signal();
                }
                catch(InterruptedException ex){
                    ex.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
            
            public int read() {
                int value=0;
                lock.lock();
                try {
                    while(queue.isEmpty()) {
                        System.out.println("			Wait for notEmpty condition");
                        notEmpty.await();
                    }
                    value=queue.remove();
                    notFull.signal();
                }catch(InterruptedException ex) {
                    ex.printStackTrace();
                }finally {
                    lock.unlock();
                }
                return value;
                
            }
        }
    
    }
    ConsumerProducer.java

    阻塞队列

    java.util.concurrent包中提三个具体的阻塞队列ArrayBlockingQueue,LinkedBlockingQueue和PriorityBlockingQueue;

    阻塞队列的方法:

    put(element e)  //在队尾插入一个元素,如果队列已满则线程进入阻塞队列等待。

    take()        //返回并删除这个队列的头,如果队列为空则线程进入阻塞队列等待。

    LinkedBlockingQueue是可以创建不受限的或受限的链队,对于不受限队列而言,put方法将永远不会阻塞。

    例子:用阻塞队列改写上面的生产者/消费者

    package test;
    import java.util.concurrent.*;
    import java.util.concurrent.locks.*;
    
    public class ConsumerProducer {
    //    public static Buffer buffer=new Buffer();
        private static ArrayBlockingQueue<Integer> buffer =new ArrayBlockingQueue<Integer>(1);
        public static void main(String args[]) {
            ExecutorService executor = Executors.newFixedThreadPool(2);
            executor.execute(new ProducerTack());
            executor.execute(new ConsumerTask());
            executor.shutdown();
        }
        private static class ProducerTack implements Runnable{
            public ProducerTack() {
                // TODO 自动生成的构造函数存根
            }
    
            @Override
            public void run() {
                try {
                    int i=1;
                    while(true) {
                        buffer.put(i);
                        System.out.println("Producer writes" + i);
                        i++;
                        Thread.sleep((int)(Math.random()*1000));
                    }
                }catch(InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
            
        }
    
        private static class ConsumerTask implements Runnable{
            public ConsumerTask() {
                // TODO 自动生成的构造函数存根
            }
    
            public void run() {
                try {
                    while(true) {
                        System.out.println("			Consumer reads " + buffer.take());
                        Thread.sleep((int)(Math.random()*1000));
                    }
                }catch(InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
    阻塞队列改写生产者/消费者

    信号量Semaphore

    信号量用来限制访问共享资源的线程数,在访问资源之前,线程必须从信号量获取许可,在访问完资源之后,这个线程必须将许可返回给信号量。

    构造方法:Semaphore(int numberOfPermits int)  //创建一个带指定数目许可的信号量,公平策略为false

    方法: void acquire()   //获取这个信号量的许可。如果无许可可用,线程就被锁住,直到有可用许可为止

        void release()    //释放一个许可给该信号量

    避免死锁

    给资源安排一个加锁顺序,就不会发生死锁的现象了

    同步集合

    Java集合框架中的类不是线程安全的,可以通过锁定集合和同步集合保护集合中数据。

    Collections类提供六个静态方法来将集合转成同步版本,这些方法创建的集合成为同步包装类

    方法:

    Collection synchronizedCollection(Collection c) //返回同步集合

    List synchronizedList(List list) //返回同步线性表

    Map synchronizedMap(Map m) //返回同步图

    Set synchronizedSet(Set s) //返回同步规则集

    SortedMap synchronizedSortedMap(SortedMap s) //返回同步有序图

    SortedSet synchronizedSortedSet(SortedSet c) //返回同步有序规则集

    同步集合可以很安全地被多个线程并发的访问和修改

    注意:如果用迭代器对集合进行遍历时,同时对集合进行修改,迭代器就会抛出异常java.util.ConcurrentModificationExceptione而结束;

    为了避免这个错误,需要创建一个同步集合对象,并且在遍历它时获取对象上的锁。

    Set hashSet = Collections.synchronizedSet(new HashSet());//同步集合
    synchronized (hashSet){//加锁
        Iterator iterator = hashset.iterator();
        while(iterator.hasnext()){
             System.out.println(iterator.next());
        }  
    }
  • 相关阅读:
    sort exam
    一个简单的爬虫
    php双色球
    计算水果的总价格
    jquery三级导航,级联菜单精简
    判断学生成绩
    服务器信息展示
    服务器信息(二)一些常量名和时间戳的简单了解
    天气预报ajax+php(可惜用的是已经失效的api)
    mysql基础(二)
  • 原文地址:https://www.cnblogs.com/zdl2234/p/11210929.html
Copyright © 2011-2022 走看看