• Java学习(十一)


    Java在设计之初就已经考虑到了线程的问题,因此Java可以有多种方式调用线程。

    1.通过继承线程类的方式调用线程。通过对函数public void run(){……}进行覆盖来实现相关的程序

    2.通过调用接口Runnable来调用线程。首先定义一个类,在类中定义一个函数为public void run(){……}用于存放相关程序。

    3.通过Lambda表达式的匿名类来开启新的线程。

    具体代码如下:

     1 package helloWorld;
     2 
     3 class AndyThread1 extends Thread {
     4     public void run()
     5     {
     6         for(int i=0;i<20;i++)
     7         {
     8             System.out.print(i+" ");
     9             try
    10             {
    11             Thread.sleep(1000);
    12             }catch(Exception e)
    13             {
    14                 e.printStackTrace();
    15             }
    16         }
    17         System.out.println();
    18     }
    19 
    20 }
    21 
    22 class AndyThread2 implements Runnable
    23 {
    24     public void run()
    25     {
    26         for(int i=20;i<30;i++)
    27         {
    28             System.out.print(i+" ");
    29             try
    30             {
    31                 Thread.sleep(1000);
    32             }catch(Exception e)
    33             {
    34                 e.printStackTrace();
    35             }
    36         }
    37         System.out.println();
    38     }
    39 }
     1                 AndyThread1 at1=new AndyThread1();
     2         AndyThread2 at2=new AndyThread2();
     3         Thread thread=new Thread(at2);
     4         new Thread(()->{
     5             for(int i=-10;i<0;i++)
     6             {
     7                 System.out.print(i+" ");
     8                 try{
     9                     Thread.sleep(1000);
    10                 }catch(Exception e)
    11                 {
    12                     e.printStackTrace();
    13                 }
    14                 }
    15             System.out.println();
    16             }).start();
    17             at1.start();
    18             thread.start();
    19 显示结果为:
    20 0 -10 20 1 -9 21 2 22 -8 -7 23 3 -6 4 24 25 -5 5 6 -4 26 27 -3 7 28 -2 8 -1 29 9 10 11 12 13 14 15 16 17 18 19 (结果不唯一,但形式一致)

    实现Runnable接口比继承Thread类所具有的优势:

    1):适合多个相同的程序代码的线程去处理同一个资源

    2):可以避免java中的单继承的限制

    3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

    4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

    线程的状态有:start、join、yield、run、notify

    线程具有优先级,分别为MIN_PRIORITY(1)、NORMAL_PRIORITY(5)、MAX_PRIORITY(10)

    线程中存在守护线程,可以利用函数setDeamon()将某个线程设置为守护线程。主线程退出后守护线程会自动中断,否则守护线程会一直存在。

    线程的调用过程有时会出现不同步的情况。因此,对于需要数据必须同步的情况,如生产消费者情况,则可以调用Java中锁的概念,也称为monitor。下面对其进行简述。

    锁的概念是Java为了解决多个线程处理数据不同步的情况下提出来的,使用关键字为synchronize。可以在语句段前使用synchronize(this)或者synchronized(other)来声明。如果整个函数都需要同步,那么在函数前可以直接使用synchronized。在多个线程中,只有获得锁的线程才可以执行程序,否则就需要等待。用户也可以设置线程的解锁,可以使用wait()函数,在释放锁前利用notify()或者notifyAll()函数来通知其他线程可以获取锁了,其他线程的wait()函数自动解除。线程中还有比较常用的函数,如获取线程状态的函数getState()和getName()、getClass(),分别表示线程的状态、获取线程的名字、获取线程所在的类名。

    以下是生产者消费者代码。在一个数组中指定数组长度为length,随机产生的数字个数不能超过此数组长度范围,逐个取出的数字也不能超过此数组的范围。

     1 class ProductorConsumer extends Thread
     2 {
     3     private static int[] arr; 
     4     private static int index;
     5     public ProductorConsumer()
     6     {
     7         index=0;
     8         ProductorConsumer.arr=new int[5];//默认数组长度为5
     9     }
    10     public ProductorConsumer(int length)
    11     {
    12         index=0;
    13         ProductorConsumer.arr=new int[length];
    14     }
    15     public ProductorConsumer(int[] arr)
    16     {
    17         index=arr.length-1;
    18         ProductorConsumer.arr=new int[arr.length];//自定义数组
    19         ProductorConsumer.arr=arr;        
    20     }
    21     
    22     synchronized public void productor() throws InterruptedException
    23     {
    24         if(index<arr.length)
    25         {
    26             arr[index]=(int) (10*Math.random());
    27             System.out.printf("productor: arr[%d] = %d
    ",index,arr[index]);
    28             index++;
    29             this.notifyAll();
    30         }
    31         else
    32         {
    33             System.out.println("productor: wait");
    34             this.wait();                
    35         }
    36     }
    37     
    38     synchronized public void consumer() throws InterruptedException
    39     {
    40         if(index>=0)
    41         {
    42             index--;
    43             System.out.printf("consumer: arr[%d] = %d
    ",index,arr[index]);
    44             this.notifyAll();
    45         }
    46         else
    47         {
    48             System.out.println("consumer: wait");
    49             this.wait();
    50         }
    51     }
    52 }
            ProductorConsumer pc;
            for (int i = 0; i < 10; i++) {
                pc = new ProductorConsumer();
                pc.start();
                try {
                    pc.productor();
                    pc.consumer();
                } catch (InterruptedException ite) {
                    ite.printStackTrace();
                }
            }
    结果为:
    productor: arr[0] = 6
    consumer: arr[0] = 6
    productor: arr[0] = 5
    consumer: arr[0] = 5
    productor: arr[0] = 8
    consumer: arr[0] = 8
    productor: arr[0] = 3
    consumer: arr[0] = 3
    productor: arr[0] = 8
    consumer: arr[0] = 8
    productor: arr[0] = 1
    consumer: arr[0] = 1
    productor: arr[0] = 7
    consumer: arr[0] = 7
    productor: arr[0] = 4
    consumer: arr[0] = 4
    productor: arr[0] = 7
    consumer: arr[0] = 7
    productor: arr[0] = 7
    consumer: arr[0] = 7

    在Java.util.包中有一个类名为java.util.concurrent.atomic.AtomicInteger,可以很安全的解决多线程同时访问造成的安全问题。直译名为原子整数,即此整数不会同时被两个线程访问。

     1 class AtomicInte {
     2     static AtomicInteger ai = new AtomicInteger(0);
     3     static int n;
     4     static int num;
     5 
     6     public AtomicInte() {
     7         AtomicInte.n = 0;
     8         AtomicInte.num = 100;
     9     }
    10 
    11     public AtomicInte(int n, int num) {
    12         AtomicInte.n = n;
    13         AtomicInte.num = num;
    14     }
    15 
    16     public void test() throws InterruptedException {
    17         Thread[] thread = new Thread[num];
    18         for (int i = 0; i < num; i++) {
    19             thread[i] = new Thread() {
    20                 public void run() {
    21                     n++;
    22                     ai.getAndIncrement();
    23                 }
    24             };
    25         }
    26         for (int i = 0; i < num; i++) {
    27             thread[i].start();
    28             Thread.sleep(1);//不加sleep会出错,即同时开启多个线程,中间没有间断,导致有些线程并未开启
    29         }
    30     }
    31 
    32     public void print() {
    33         System.out.println(n + " " + ai);
    34     }
    35 }
    1         AtomicInte ai = new AtomicInte();
    2         try {
    3             ai.test();
    4         } catch (InterruptedException ite) {
    5             ite.printStackTrace();
    6         }
    7         ai.print();

    Java.util.concurrent包中还有一些方便的类用于防止多线程同时操作所产生的错误。如CopyOnWriteArrayList、CopyOnWriteSet,适于很少写入而读取很频繁的对象;ConcurrentHashMap中的putlfAbsent()、remove()、replace();ArrayBlockingQueue等

    以下为ArrayBlockingQueue的实例:

     1 class Productor extends Thread
     2 {
     3     BlockingQueue<Integer> queue;
     4     public Productor(){}
     5     public Productor(BlockingQueue<Integer> queue)
     6     {
     7         this.queue=queue;
     8     }
     9     
    10     public void run()
    11     {
    12         int temp=0;
    13         try
    14         {
    15             for(int i=0;i<10;i++)
    16             {
    17                 temp=(int)(20*Math.random());
    18                 queue.put(temp);
    19                 Thread.sleep(10);
    20                 System.out.println("Productor: "+temp);
    21             }
    22         }catch(InterruptedException ite)
    23         {
    24             ite.printStackTrace();
    25         }
    26     }
    27 }
    28 
    29 class Customer extends Thread
    30 {
    31     BlockingQueue<Integer> queue;
    32     public Customer(){}
    33     public Customer(BlockingQueue<Integer> queue)
    34     {
    35         this.queue=queue;
    36     }
    37     
    38     public void run()
    39     {
    40         try
    41         {
    42             for(int i=0;i<10;i++)
    43             {
    44                 Integer integer=queue.take();
    45                 System.out.println("Consumer: "+integer);
    46             }
    47         }catch(InterruptedException ite)
    48         {
    49             ite.printStackTrace();
    50         }
    51     }
    52 }
    1         BlockingQueue<Integer> queue=new ArrayBlockingQueue<Integer>(3);
    2         new Thread(new Productor(queue)).start();
    3         new Thread(new Customer(queue)).start();;

    线程池相关的类:ExecutorService接口、ThreadPoolExecutor类、Executor类

    线程池的创建可以用ExecutorService pool=executors.newCachedThreadPool();

    具体可见示例:

     1 class ThreadPool implements Runnable
     2 {
     3     int state;
     4     public ThreadPool() {
     5         state = 0;
     6     }
     7 
     8     public ThreadPool(int state) {
     9         this.state = state;
    10     }
    11 
    12     public void run() {
    13         for (int i = 0; i < 5; i++)
    14             if (state == 0)
    15                 System.out.println("Good morning, Andy");
    16             else if (state == 1)
    17                 System.out.println("Good afternoon, Andy");
    18             else if (state == 2)
    19                 System.out.println("Good evening, Andy");
    20             else if (state == 3)
    21                 System.out.println("Good night, Andy");
    22             else
    23                 System.out.println("Good bye, Andy");
    24     }
    25 }
     1         ExecutorService pool=Executors.newCachedThreadPool();
     2         ThreadPool tp1=new ThreadPool(0);
     3         ThreadPool tp2=new ThreadPool(1);
     4         ThreadPool tp3=new ThreadPool(2);
     5         ThreadPool tp4=new ThreadPool(3);
     6         ThreadPool tp5=new ThreadPool(4);
     7         pool.execute(tp1);
     8         pool.execute(tp2);
     9         pool.execute(tp3);
    10         pool.execute(tp4);
    11         pool.execute(tp5);
    12 结果为:
    13 Good morning, Andy
    14 Good morning, Andy
    15 Good morning, Andy
    16 Good afternoon, Andy
    17 Good afternoon, Andy
    18 Good afternoon, Andy
    19 Good afternoon, Andy
    20 Good afternoon, Andy
    21 Good bye, Andy
    22 Good bye, Andy
    23 Good bye, Andy
    24 Good evening, Andy
    25 Good evening, Andy
    26 Good evening, Andy
    27 Good evening, Andy
    28 Good evening, Andy
    29 Good morning, Andy
    30 Good morning, Andy
    31 Good night, Andy
    32 Good night, Andy
    33 Good night, Andy
    34 Good night, Andy
    35 Good night, Andy
    36 Good bye, Andy
    37 Good bye, Andy

    Java中为了使多线程操作更加安全,除了隐式锁外还有显式锁。显式锁在java.util.concurrent.locks中,含有Lock接口、ReentrantLock类:lock()、tryLock()、unlock();含有ReadWriteLock接口、ReentrantReadWriteLock类:writeLock().lock()、readLock().lock()

  • 相关阅读:
    Linux之cd、pwd、mkdir、rmdir
    Linux之目录结构配置
    Linux之chgrp
    Linux之chown
    Linux之chmod
    Linux之用户组、文件权限详解
    Linux命令之shutdown
    Linux命令之man
    Git-.gitignore配置
    Linux内核移植到JZ2440
  • 原文地址:https://www.cnblogs.com/2Bthebest1/p/8423932.html
Copyright © 2020-2023  润新知