Java 多线程 详解

进程

进程是处于运行过程中的程序,具有独立的功能,是系统进行资源分配和调度的独立单位

  • 独立性
    • 进程是系统中独立存在的实体,他拥有独立的资源,每一个进程都拥有自己私有的地址空间,在没有经过进程本身允许的情况下,一个进程不能直接访问其他进程的地址空间
  • 动态性
    • 进程是一个正在系统中活动的指令集合,包含了时间 的概念,具有 自己的生命周期和状态
  • 并发性
    • 在单个处理器上,多个进程可以并发的执行,并且在执行时它们彼此之间不会互相影响
  • 并发和并行的区别
    • 并行
    1. 在同一时刻,有多条指令在多个处理器上同时进行
    • 并发
    1. 在同一时刻,莫一个处理器只能执行一条指令;
    1. 多个进程的指令可以将快速的轮换执行,使得在宏观上具有多个进程同时执行的效果
      对于多核计算机,当进程数多于核心数时,也会存在并发的行为

线程

  1. 线程扩展了进程的概念,使得同一个进程可以同时并发的处理多个认为
  2. 线程是进程的组成部分,一个进程可以拥有多个线程,一个线程必须有一个父进程
  3. 线程不拥有系统资源,他与父进程里的其他进程共享父进程所拥有的全部系统资源
    系统可以同时执行多个任务,每个任务就是进程
    进程可以执行多个任务,每个任务就是线程

线程的优点

  • 容易共享内存
    1. 线程之间不能共享内存,但线程之间共享内存非常容易,因为与分隔的进程相比
    1. 线程之间的隔离程度要小,他们共享内存,文件句柄,其他每个进程应有的状态;
  • 运行效率更高
    1. 系统创建进程时要为其分配系统资源,但创建线程时不需要,所以线程的运行效率更高
  • 编程方式简单
  • java内置了多线程功能的支持,并不是简单地对操作系统的底层进行调度,编程更方便

java线程的创建

  • java使用Thread类创建线程,所有的线程对象都必须是Thread类或者他的子类的实例
  • 线程用于完成一定的任务(执行一段程序流 ),java使用线程执行体来代表这段程序流
  • 线程的使用过程;定义线程执行体>创建线程对象>调用线程对象的方法以启动线程

继承Thread类

  • 定义Thread类的子类,并重写该类的run()方法
  • 创建Thread类的子类的实例,即创建线程对象
  • 调用线程对象的start()方法,即启动这个线程
Java 多线程 详解

实现Runnable接口

  1. 定义Runnable接口的实现类,并且实现该接口的run()方法(线程体)
  2. 创建Runnable实现类的实例,并且以此作为target来创建Thread对象
  3. 调用Thread对象的start()方法来启动线程
  4. Java 多线程 详解

实现Callable接口

  1. 定义Callable接口的实现类,并且实现该接口的call()方法 (线程体)
  2. 创建Callable接口的实例,并且使用Futrue接口来包装Callable对象,最后使用Futrue对象(线程的返回值)作为target来创建Thread对象
  3. 调用Thread对象的start()方法来启动线程
  4. 调用Futrue对象的get()方法来获取线程的返回值
Java 多线程 详解

三种方式的比较

继承父类的方式

  • 优点:编程比较简单;
  • 缺点:线程类已经继承了Thread类,所以不能再继承其他的父类;
    实现接口的方式
  • 优点:线程类只实现了接口,还可以继承于其他的父类;
  • 缺点:编程比较麻烦;
  • Java 多线程 详解
public static void main(String[] args) {  //        第一种方式 //         new First().start(); //         new First().start();         第二种方式 // //         new Thread(new Second()).start(); //        new Thread(new Second()).start();   //        第三种方式          FutureTask<String> task0 = new FutureTask<>(new Third());         FutureTask<String> task1= new FutureTask<>(new Third());          new Thread(task0).start();         new Thread(task1).start();            主线程         for (int i = 0; i < 10; i++) {             System.out.println(Thread.currentThread().getName() + "t" + i);         }      }      private static class First extends Thread{         @Override         public void run() {             for (int i = 0; i < 10; i++) {                 System.out.println(Thread.currentThread().getName()+"t"+i);             }         }     }      private static class Second implements  Runnable{          @Override         public void run() {             for (int i = 0; i < 10; i++) {                 System.out.println(Thread.currentThread().getName()+"t"+i);             }         }     }       private static class Third  implements Callable<String>{          @Override         public String call() throws Exception {             for (int i = 0; i < 10; i++) {                 System.out.println(Thread.currentThread().getName()+"t"+i);             }             return Thread.currentThread().getName();         }     }    } 

线程的生命周期

当线程被创建后,他不会立刻进入运行状态,也不会一直处于运行状态
在线程的生命周期中,需要经过如下5种状态

  1. 新建(New)
  2. 就绪(Ready)
  3. 运行(Running)
  4. 阻塞(Blocked)
  5. 死亡(Dead)
  6. Java 多线程 详解
 public static void main(String[] args) throws InterruptedException {        Thread thread0=new Thread(new ThreadTask(),"线程1");         Thread thread1 = new Thread(new ThreadTask(), "线程2");          for (int i = 0; i < 100; i++) {             System.out.println(Thread.currentThread().getName() + "ttttt" + i);             if (i==0){ //                子线程就绪                 thread0.start();                 thread1.start(); //                主进程就绪    //             Thread.yield(); //                主线程阻塞                 Thread.sleep(10);             }           } //   子线程死亡      }        private static class ThreadTask implements Runnable{          @Override         public void run() {             for (int i = 0; i < 10; i++) {                 System.out.println(Thread.currentThread().getName()+"tttttttt"+i);             }         }     }    }  

控制线程的手段

线程休眠
Thread类提供了休眠方法,可以让当前线程暂停一段时间

static void sleep(long millis)
static void sleep(long millis ,int nanos)

Java 多线程 详解
等待线程
Thread类提供了等待方法,可以让调用方等待该线程直至他死亡
void join()
void join(long millis)

void join(long millis,int nanos)
Java 多线程 详解

后台线程

  1. 后台线程,也叫做守护线程,或者精灵线程
  2. 他是后台运行的,他的任务是为其他线程提供服务
  3. 如果所有前台线程死亡,则后台线程会自动死亡
  4. 线程默认前台线程 ,Thread类提供如下方法来设置后台线程
    • void setDaemo(boolean on)
    • boolean isDaemo()
Java 多线程 详解

线程的优先级

  1. 线程运行时拥有优先级,优先级高的线程则拥有较多的运行机会
  2. 线程默认的优先级与他的父线程相同,而主线程具有普通优先级
  3. Thread类提供了如下成员,来处理线程的优先级
    • static int MAX_PRIORITY;10
    • static int MIN_PRIORITY;1
    • static int NORM_PROORITY;5
    • int getPriority()
    • void setPriority(int newPriority)
Java 多线程 详解
  public static void main(String[] args) throws InterruptedException {  //        testJoinThread(); //        testDamonThread();         taskPriorityThread();     }       private  static class JoinThreadTest implements  Runnable{          @Override         public void run() {             for (int i = 0; i < 30; i++) {                 System.out.println(Thread.currentThread().getName() + "tttttt" + i);             }         }     }      private static void testJoinThread() throws InterruptedException {         new Thread(new JoinThreadTest()).start();         for (int i = 0; i < 30; i++) {             System.out.println(Thread.currentThread().getName() + "tt" + i);             if (i==10){                 Thread thread = new Thread(new JoinThreadTest());                 thread.start();                 thread.join();             }         }     }      private static class DaemonThreadTask implements Runnable{          @Override         public void run() {             for (int i = 0; i < 100; i++) {                 System.out.println(Thread.currentThread().getName() + "ttttttttttttttttt" + i);              }         }     }      private static void testDamonThread(){ //        后台线程         Thread thread = new Thread(new DaemonThreadTask());         thread.setDaemon(true);         thread.start();         for (int i = 0; i < 10; i++) {             System.out.println(Thread.currentThread().getName() + "t" + i);         }     }      private static class PriorityThreadTask implements Runnable{          @Override         public void run() {             for (int i = 0; i < 1000; i++) {                 System.out.println(Thread.currentThread().getName() + "t" + i);             }         }     } //   线程优先级      private static void taskPriorityThread(){         Thread thread0 = new Thread(new PriorityThreadTask());         Thread thread1 = new Thread(new PriorityThreadTask());  //        System.out.println(Thread.currentThread().getPriority()); //        System.out.println(thread0.getPriority()); //        System.out.println(thread1.getPriority());         thread0.setPriority(Thread.MAX_PRIORITY);           thread1.setPriority(Thread.MIN_PRIORITY);         thread1.start();         thread0.start();     }  

线程安全问题

     public static void main(String[] args) {          Ticket ticket = new Ticket(100);         SellTask task = new SellTask(ticket);          new Thread(task, "DJK").start();          new Thread(task, "DXL").start();         new Thread(task, "DXL1").start();         new Thread(task, "DXL2").start();         new Thread(task, "DXL3").start();      }      private static class Ticket{          private int amount;          public Ticket(int amount) {             this.amount = amount;         }          public int getAmount() {             return amount;         }          public void setAmount(int amount) {             this.amount = amount;         }          public void buy(int amount){              if (this.amount<amount){                 throw new IllegalArgumentException("余量不足");             }  //            检验花费一些时间             try {                 Thread.sleep(1);             } catch (InterruptedException e) {                  e.printStackTrace();             }             this.amount-=amount;             String name = Thread.currentThread().getName();             System.out.println(name + " 购买成功  剩余数量"+this.amount);          }     }      private static class SellTask implements Runnable{          private Ticket ticket;          public SellTask(Ticket ticket) {             this.ticket = ticket;         }          @Override         public void run() {            ticket.buy(1);         }     }  
Java 多线程 详解

线程同步

同步 ;对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一性化的现象
1. 加锁>修改>解锁
2. 加锁机制可保障在任何一时刻只有一个线程可以进入共享资源代码区(临界区)但是加锁 解锁是有代价的 就是牺牲程序的性能

  • 无需显示指定同步监视器,在成员方法中默认为this,在静态方法中它默认为当前的类
  • Java 多线程 详解
  • synchronized 特点
    1. 将加锁及解锁的过程固化了,便携性有余,但灵活性不足
    1. 某个线程在访问同步代码时阻塞了,其他线程只能等待,影响程序的执行效率
    1. 在访问共享资源时,对于多个线程同时读的场景,实际不会产生任何冲突,但是synchronized不会区分这种场景,依然做加锁处理,还是影响程序的执行效率
  • Lock

    Java 多线程 详解 Java 多线程 详解
    Java 多线程 详解
    /**  *  * 线程同步案例(同步代码块,同步方法,同步锁)  *  */   public class ThreadDemo5 {      public static void main(String[] args) {          Ticket ticket = new Ticket(100);         SellTask task = new SellTask(ticket);         new Thread(task, "DJK").start();         new Thread(task, "DXL").start();         new Thread(task, "DXL1").start();         new Thread(task, "DXL2").start();         new Thread(task, "DXL3").start();      }      private static class Ticket{  //        同步锁         private Lock lock =new ReentrantLock();          private int amount;          public Ticket(int amount) {             this.amount = amount;         }          public int getAmount() {             return amount;         }          public void setAmount(int amount) {             this.amount = amount;         }  //        同步方法         public synchronized   void buy(int amount){              if (this.amount<amount){                 throw new IllegalArgumentException("余量不足");             }  //            检验花费一些时间             try {                 Thread.sleep(1);             } catch (InterruptedException e) {                 e.printStackTrace();             } //            通过检验成功购票               lock.lock(); //            synchronized (this){                 this.amount-=amount;                 String name = Thread.currentThread().getName();                 System.out.println(name + " 购买成功  剩余数量"+this.amount);  //            }             lock.unlock();//手动解锁         }     }      private static class SellTask implements Runnable{          private Ticket ticket;          public SellTask(Ticket ticket) {             this.ticket = ticket;         }          @Override         public void run() {             ticket.buy(1);         }     }     } 

    死锁

    当两个线程互相等待对方释放同步监视器时会发生死锁,应避免这种情况的出现

    • 避免多次锁定
      1. 尽量避免同一个线程对多个同步监视器进行锁定
    • 按相同的顺序加锁
      1. 如果多个线程需要对多个同步监视器加锁,则应该保证他们以相同的顺序请求加锁
    • 使用可以超时释放的锁
      1. 调用Lock对象的tryLock(time,unit)方法,当超过指定时间后它会自动释放锁
    package 线程;  /**  *  * 死锁  *  */   public class ThreadDemo6 {      public static void main(String[] args) {         String a="A";         String b="B";         new Thread(new FirstTask(a,b)).start();         new Thread(new SecondTask(a,b)).start();       }      private static class FirstTask implements Runnable{          private Object a;         private Object b;          public FirstTask(Object a, Object b) {             this.a = a;             this.b = b;         }          @Override         public void run() {            synchronized (a){                try {                         Thread.sleep(10);                 } catch (InterruptedException e) {                    e.printStackTrace();                }                 synchronized (b){                    System.out.println("First");                }            }         }     }      private static class SecondTask implements Runnable{          private Object a;         private Object b;          public SecondTask(Object a, Object b) {             this.a = a;             this.b = b;         }          @Override         public void run() {             synchronized (b){                 try {                      Thread.sleep(10);                  } catch (InterruptedException e) {                     e.printStackTrace();                 }                  synchronized (a){                     System.out.println("First");                 }             }         }     }  }  
    Java 多线程 详解

    线程通信

    1. 在某些业务中,a线程负责修改数据,b线程负责使用数据
    2. 在数据修改前,b线程处于等待状态,直至a线程的通知
    3. 在数据修改后,a线程通过某种机制,通知b线程去使用数据
    Java 多线程 详解
    Java 多线程 详解
    lock
    Condition condition=lock.newCondition();
    Java 多线程 详解
     public class ThreadDemo7 {      public static void main(String[] args) throws InterruptedException {          Product product = new Product(0);          for (int i = 0; i < 100; i++) {            new Thread(new BuyTask(product),"顾客"+i).start();         }          try {             Thread.sleep(100);        } catch (InterruptedException e) {             e.printStackTrace();        }         for (int i = 0; i < 10; i++) {          //   Thread.sleep(100);             System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++==");             new Thread(new SellTask(product),"商家"+i).start();         }       }      private static class Product{          private int amount;         private int stock;          public Product(int amount) {             this.amount = amount;         }          public int getStock() {             return stock;         }          public void setStock(int stock) {             this.stock = stock;         }         public int big(int stock){             return this.stock=this.stock+stock ;         }     }      private static class BuyTask implements Runnable{          private Product product;          public BuyTask(Product product) {             this.product = product;         }           @Override         public void run() {              synchronized (product){                  String name=Thread.currentThread().getName();                 while (product.getStock()==0){                     try {                         System.out.println(name + "已做好准备,等待抢购。。。。。。。。。。。");                         product.wait();                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                 }                 product.setStock(product.getStock()-1);                 System.out.println(name + "抢到1件商品,剩余PPPPPPPPPPPPPPPPPPPPPPPPPPP  " + product.getStock());             }          }     }      private static class SellTask implements Runnable{          private Product product;          public SellTask(Product product) {             this.product = product;         }          @Override         public void run() {              synchronized (product){                  product.big(10);                 String name = Thread.currentThread().getName();                 System.out.println(name + "上架了10件商品,剩余库存"+product.getStock());                 product.notifyAll();              }         }     }   }  
    package 线程;  import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;  /**  *  * 线程通信(lock)  *  *  */   public class ThreadDemo8 {      private static Lock lock=new ReentrantLock();      private static Condition condition=lock.newCondition();      public static void main(String[] args) throws InterruptedException {          Product product = new Product(0);          for (int i = 0; i < 100; i++) {             new Thread(new BuyTask(product),"顾客"+i).start();         }          try {             Thread.sleep(100);         } catch (InterruptedException e) {             e.printStackTrace();         }         for (int i = 0; i < 10; i++) {             //   Thread.sleep(100);             System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++==");             new Thread(new SellTask(product),"商家"+i).start();         }       }      private static class Product{          private int amount;         private int stock;           public Product(int amount) {             this.amount = amount;         }          public int getStock() {             return stock;         }          public void setStock(int stock) {             this.stock = stock;         }         public int big(int stock){             return this.stock=this.stock+stock ;         }     }      private static class BuyTask implements Runnable{          private Product product;          public BuyTask(Product product) {             this.product = product;         }           @Override         public void run() {               lock.lock();                 String name=Thread.currentThread().getName();                 while (product.getStock()==0){                     try {                         System.out.println(name + "已做好准备,等待抢购。。。。。。。。。。。");                         condition.await();                     } catch (InterruptedException e) {                         e.printStackTrace();                     }                 }                 product.setStock(product.getStock()-1);                 System.out.println(name + "抢到1件商品,剩余PPPPPPPPPPPPPPPPPPPPPPPPPPP  " + product.getStock());              lock.unlock();          }     }      private static class SellTask implements Runnable{          private  Product product;          public SellTask(Product product) {             this.product = product;         }          @Override         public void run() {               lock.lock();                  product.big(10);                 String name = Thread.currentThread().getName();                 System.out.println(name + "上架了10件商品,剩余库存"+product.getStock());                 condition.signalAll();               lock.unlock();         }     } }  
    Java 多线程 详解

    阻塞队列

    · 生产消费者模式

    1. 某个模块负责产生数据,另一个模块处理数据
    2. 产生数据的模块被称为生产者,处理数据的模块被称为消费者
    3. 需要有一个缓冲区位于生产者与消费者之间,作为沟通的桥梁
    4. 生产者只负责把缓冲区,而消费者从缓冲区取出数据
    5. Java 多线程 详解
      BlockingQueue
    • BlockingQueue是Queue的子接口
    • 它的主要作用是作为线程通信的工具
    • BlockingQueue增加了2个支持阻塞的方法
      1. void put(E e)尝试把元素e放入队列中,如果该队列的元素已满,则阻塞线程;
      1. void take()尝试从队列的头部取出元素,如果该队列的元素以空,则阻塞线程
    /**  *  * 阻塞队列  *  */   public class ThreadDemo9 {       public static void main(String[] args) {          BlockingQueue<Long> queue = new ArrayBlockingQueue<>(10);         new Thread(new Producer(queue),"P1").start();         new Thread(new Producer(queue),"P2").start();         new Thread(new Producer(queue),"P3").start();         new Thread(new Producer(queue),"P4").start();         new Thread(new Producer(queue),"P5").start();         new Thread(new Customer(queue),"x2").start();         new Thread(new Customer(queue),"x3").start();         new Thread(new Customer(queue),"x4").start();         new Thread(new Customer(queue),"x5").start();         new Thread(new Customer(queue),"x6").start();      }      private static class Producer implements Runnable{          private BlockingQueue<Long> queue;          public Producer(BlockingQueue<Long> queue) {             this.queue = queue;         }          @Override         public void run() {              while (true){                 try {                     Thread.sleep(new Random().nextInt(1000));                     queue.put(System.currentTimeMillis());                     String name=Thread.currentThread().getName();                     System.out.println(name + "生产了一条数据,剩余" + queue.size());                 } catch (InterruptedException e) {                     e.printStackTrace();                 }              }          }     }       private static class Customer implements  Runnable{          private BlockingQueue<Long> queue;          public Customer(BlockingQueue<Long> queue) {             this.queue = queue;         }          @Override         public void run() {            while (true){                try {                    Thread.sleep(new Random().nextInt(1000));                    queue.take();                    String name=Thread.currentThread().getName();                    System.out.println(name + "消费了一条数据,剩余" + queue.size());                } catch (InterruptedException e) {                    e.printStackTrace();                }            }          }     }  }  
    Java 多线程 详解

    线程组

    ThreadGroup类代表线程组,它可以包含一批线程,并对这些线程进行统一的管理

      1. 每个线程都有对应的线程组,若程序未显示指定线程的线程组,则线程属于默认线程组
      1. 默认情况下,子线程与它的父线程属于同一个线程组,而main线程则归属于main线程组
      1. 一旦线程加入了某个线程组,则该线程将一直属于这个数组,中途不允许修改其线程组

    创建线程组

    ThreadGroup的构造器
    public ThreadGroup(String name)
    public ThreadGroup(ThreadGroup parent ,String name)

    Thread的构造器
    public Thread(ThreadGroup parent ,String name)
    public Thread(ThreadGroup parent ,Runnable target)
    public Thread(ThreadGroup parent ,Runnable target,String name )

    使用线程组

    ThreadGroup中常用的处理线程的方法包括

    1. 返回线程组的名称
    2. 返回当前线程组的父线程
    3. 中断此线程组中所有的线程
    4. 设置(返回)线程组的最高优先级
    5. 设置(返回)线程组的后台线程组
    Java 多线程 详解
    /**  *  *  * 线程组  *  */   public class ThreadDemo10 {       public static void main(String[] args) throws InterruptedException {  //        主线程的线程组         ThreadGroup g = Thread.currentThread().getThreadGroup();         System.out.println(g.getName() + "," + g.isDaemon() + "," + g.activeCount());          g.list();  //         子线程的线程组         Thread thread = new Thread(new ThreadTask());         thread.start();         System.out.println(thread);  //      自定义线程组        g=new ThreadGroup("DJK");        g.setDaemon(true);        thread=new Thread(g,new ThreadTask());        thread.start();         System.out.println(thread);  //        销毁的后台线程组         Thread.sleep(100);         System.out.println(g.isDestroyed());  //        异常处理器         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {             @Override             public void uncaughtException(Thread t, Throwable e) {                 System.out.println(t + "----->" + e);             }         });         System.out.println(3 / 0);      }      private static class ThreadTask implements Runnable{           @Override         public void run() {             System.out.println(System.currentTimeMillis());         }     }    }  
    Java 多线程 详解

    线程池

    • 启动线程的成本是比较高的,通过线程池可以实现线程复用,从而提高 性能
    • 线程池可以 控制程序中的线程数量,避免超出系统负荷,导致系统崩溃
    Java 多线程 详解

    创建线程池

    1. ExecutorService接口代表线程池;
    2. ScheduledExecutorService是其子接口,代表可执行定时任务的线程池;
    3. Executors是一个工厂类,该类中包含了若干个静态方法,用来创建线程池:
      ExecutorService newFixedThreadPool(int nThreads)
      ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

    使用线程池

    Java 多线程 详解
    /**  *  *  * 线程池  *  */   public class ThreadDemo11 {      private static ScheduledExecutorService schedulePoo1= Executors.newScheduledThreadPool(3);     private static ExecutorService threadPoo1=Executors.newFixedThreadPool(3);       public static void main(String[] args) {              Runnable threadTask=new Runnable() {             @Override             public void run() {                  System.out.println(Thread.currentThread().getName() + "execute a thread task");             }         };          for (int i = 0; i < 10; i++) {              threadPoo1.submit(threadTask);         }          Runnable scheduleTask=new Runnable() {             @Override             public void run() {                  System.out.println(Thread.currentThread().getName() + " execute a schedule task");             }         };          for (int i = 0; i < 6; i++) {              schedulePoo1.scheduleAtFixedRate(scheduleTask,5,3, TimeUnit.SECONDS);         }              }  }  

    Java 多线程 详解
    强制结束的结果如上

    ForkJoinPool

    1. Fork/Join是一种思想,旨在充分利用多核资源,
      用于执行并行任务;
    2. ForkJoinPool是ExecutorService的实现类,
      是上述思想的实现;
    3. 它的做法是,将一个大的任务分割成若干个小任务,
      最终汇总每个小任务结果,从而得到大任务的结果。
      Java 多线程 详解

    创建ForkJoinPool

    • 构造器
      ForkJoinPoll(int parallelism)
      根据指定的并行级别,创建一个ForkJoinPool;
      ForkJoinPool()
      根据计算机的核心数,创建一个ForkJoinPool

    使用ForkJoinPool

    • 常用方法
    • public ForkJoinTask submit(ForkJoinTask task) {}
    • ForkJoinTask
    1. 代表一个可以并行执行的任务,是Future的实现类;
    2. RecursiveAction、RecursiveTask是它的子类;
    3. RecursiveAction代表没有返回值的任务,RecursiveTask代表有返回值的任务
    /**  *  *  * ForkJoinPool  *  */   public class ThreadDemo12 {       public static void main(String[] args) throws ExecutionException, InterruptedException {         int[] nums=new int[100];         for (int i =1 ; i <=100; i++) {             nums[i-1]=i;         }          ForkJoinPool pool=new ForkJoinPool();         Future<Integer> future=pool.submit(new FjTask(nums,0,nums.length-1));         System.out.println(future.get());      }       private static class FjTask extends RecursiveTask<Integer>{          private static final int THRESHOLD=10;         private int[] nums;          private  int start,end;          public FjTask(int[] nums, int start, int end) {             this.nums = nums;             this.start = start;             this.end = end;         }          @Override         protected Integer compute() {             System.out.printf("%-25st%2d,%2dn",Thread.currentThread().getName(),start,end);              Integer sum=0;             if (end-start<THRESHOLD){                 for (int i=start;i<=end;i++){                     sum+=nums[i];                 }              }else {                 int middle=(start+end)/2;                 FjTask left=new FjTask(nums,start,middle);                 FjTask right=new FjTask(nums,middle+1,end);                 left.fork();                 right.fork();                 sum=left.join()+right.join();             }             return sum;         }     }  }  
    Java 多线程 详解

    ThreadLocal

    ThreadLocal是一个工具类,可以将数据绑定到当前线程上,从而实现线程间数据的隔离:

    • 将数据绑定到当前线程之上
      public void set(T value) {}
    • 返回当前线程已绑定的数据
      public T get() {}
    • 删除当前线程已绑定的数据
      public void remove() {}
    /**  *  *ThreadLocal  *  */    public class ThreadDemo13 {      private static ThreadLocal<Object> threadLocal= new ThreadLocal<>();      public static void main(String[] args) {         new Thread(new ThreadTask(100)).start();         new Thread(new ThreadTask(300)).start();         new Thread(new ThreadTask(400)).start();         new Thread(new ThreadTask(500)).start();         new Thread(new ThreadTask(600.67645)).start();      }       public static void first(){         System.out.println(Thread.currentThread().getName() + " execute first");          second();      }      public static void second(){          System.out.println(Thread.currentThread().getName() + " execute second");          third();     }      public static void third(){         System.out.println(Thread.currentThread().getName() + " execute third ");         System.out.println(Thread.currentThread().getName() + " binding value "+threadLocal.get());     }      private static class ThreadTask implements  Runnable{          private Object value;          public ThreadTask(Object value) {             this.value = value;         }          @Override         public void run() {            threadLocal.set(value);             first();         }     } }  
    Java 多线程 详解

    线程安全集合

    • 包装不安全的集合
      对于传统的集合类,可以通过Collections将其包装成线程安全的集合:
      public static Set synchronizedSet(Set s) {}
      public static List synchronizedList(List list) {}
      public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {}

    • 线程安全的集合

    • Java 多线程 详解

    线程安全的集合

    这些类位于java.util.concurrent包下:

    • Concurrent开头的集合类
    1. 支持多线程的并发访问;
    2. 通过加锁处理,保证了并发写入的安全性,而并发读取是无需加锁的;
    • CopyOnWrite开头的集合类
    1. 并发读取时,直接读取集合本身,无需加锁;
    2. 并发写入时,该集合会在底层复制一份新数组,然后对新数组进行写入操作
    版权声明:玥玥 发表于 2021-08-04 5:42:20。
    转载请注明:Java 多线程 详解 | 女黑客导航