第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)

静态代理

 package com.kuang.demo03;
 //静态代理模式总结
 //真实对象和代理对象都要实现同一个接口
 //代理对象要代理真实角色
 //好处:
  //代理对象可以做很多真实对象做不了的事情
  //真实对象专注做自己的事情
 public class StacticProxy {
     public static void main(String[] args) {
         You you = new You();//你要结婚
         new Thread(()->System.out.println("I Love you")).start();
         new WeddingCompany(new You()).HappyMarry();
 ​
       // WeddingCompany weddingCompany = new WeddingCompany(you);
         //weddingCompany.HappyMarry();
    }
 }
 ​
 interface Marry{
 ​
 ​
     void HappyMarry();
 ​
 }
 //真实角色 你去结婚
 class You implements  Marry{
    @Override
     public void HappyMarry(){
        System.out.println("秦老师要结婚了,超开心");
 ​
    }
 }
 //代理角色,帮助你结婚
 class WeddingCompany implements Marry{
     //代理谁--》真实目标角色
     private Marry target;
 ​
     public WeddingCompany(Marry target) {
         this.target = target;
    }
 ​
     @Override
     public void HappyMarry(){
         before();
         this.target.HappyMarry();//这就是真实对象
         after();
 ​
    }
 ​
     private void after() {
         System.out.println("结婚之后,收尾款");
    }
 ​
     private void before() {
 ​
         System.out.println("结婚之前,布置现场");
 ​
    }
 }

Lambda表达式

第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法) 希腊字母表中排序第十一位的字母,英语名称为Lambda

避免匿名内部类定义过多

可以让代码看起来很简洁

去掉了一堆没有意义的代码,只留下核心的逻辑

其实质属于函数式编程的概念

 (params)->expression[表达式]
    (params)->statement[语句]
    (params)->{statements}
 ​
 a->System.out.println("i like lambda-->" + a);
 ​
 new Thread(()->System.out.println("多线程学习...")).start();

函数式接口的定义:

任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。

 public interface Runnable{
     public abstract void run();
 }

对于函数式接口,我们可以通过lambda表达式来创建该接口的对象。

 package com.kuang.lambda;
 /*
 推到lambda表达式
  */
 public class TestLambda1 {
 ​
     //静态内部类
    static class Like2 implements ILike{
         @Override
         public void lambda(){
             System.out.println("i like lambda2");
 ​
        }
    }
 ​
     public static void main(String[] args) {
       ILike like = new Like();
       like.lambda();
       like = new Like2();
       like.lambda();
 ​
       //4.局部内部类
         class Like3 implements ILike{
             @Override
             public void lambda() {
                 System.out.println("i like lambda3");
            }
        }
                 like = new Like3();
                 like.lambda();
 ​
                 //5.匿名内部类,没有类的名称,必须借助接口或者父类
         like = new ILike() {
             @Override
             public void lambda() {
                 System.out.println("i like lambda4");
 ​
            }
        };
         like.lambda();
 ​
         //6.用lambda简化
         like = ()->{
             System.out.println("i like lambda5");
        };
         like.lambda();
 ​
 ​
    }
        }
 ​
 ​
 //1。定义一个函数式接口
 interface ILike{//ILike是函数式接口
     void lambda();
 }
 //2.实现类
 class Like implements ILike{
     @Override
     public void lambda(){
         System.out.println("i like lambda");
 ​
    }
 }
 package com.kuang.lambda;
 ​
 public class TestLambda2 {
 ​
 ​
     public static void main(String[] args) {
         ILove love = null;
 //ctrl + shift+/:表示注释
 ​
       /* //1.lambda表示简化
         ILove love = (int a)->{
                 System.out.println("i love you1-->"+a);
             };
         //简化1,参数类型
         love = (a)->{
             System.out.println("i love you-->" +a);
         };*/
 ​
       /* //简化2,简化括号
         love = a -> {
             System.out.println("i love you-->" +a);
         };
 */
         //简化3,去掉花括号
         love = a->System.out.println("i love you-->" +a);
 ​
         //总结:lambda表达式只能有一行代码的情况下才能简化成一行,如果有多行,那么就用代码块包裹。就是花括号包裹
         //前提是接口为函数式接口
         //多个参数也可以去掉参数类型,要去掉就都去掉,必须把多个参数括在括号里面
 ​
 ​
 ​
 ​
 ​
 ​
         love.love(521);
        }
 ​
    }
 ​
 interface ILove{
     void love(int a);
 ​
 ​
 }
 ​
 package com.kuang.lambda;
 ​
 public class TestLambda2 {
 ​
 ​
     public static void main(String[] args) {
         ILove love = null;
 //ctrl + shift+/:表示注释
 ​
 ​
 ​
         //简化2,简化括号
         love = (a,b,c) -> {
             System.out.println("i love you-->" +a);
             System.out.println("i love you2-->" +b);
             System.out.println("i love you3-->" +c);
        };
 ​
 ​
 ​
 ​
 ​
 ​
         love.love(521,520,555);
        }
 ​
    }
 ​
 interface ILove{
     void love(int a,int b,int c);
 ​
 ​
 }
 ​

03线程状态

第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)

第40天学习打卡(静态代理 Lambda表达式 线程状态 线程同步 同步方法)

 方法                                         说明
 setPriority(int newPriority)         更改线程的优先级
 static void sleep(long millis)       在指定的毫秒数内让当前正在执行的线程休眠
 void join()                          等待该线程终止
 static void yield()                  暂停当前正在执行的线程对象,并执行其他线程
 void interrupt                       中断线程,别用这个方式
 boolean isAlive()                    测试线程是否处于活动状态

停止线程

不推荐使用JDK提供的stop()、destroy()方法。(已废弃)

推荐线程自己停下来

建议使用一个标志位进行终止变量

当flag = false,则终止线程运行。

 public class TestStop implements Runnable{
     //1.线程中定义线程体使用的标识
     private boolean flag = true;
     @Override
     public void run(){
         //2.线程体使用该标识
         while(flag){
             System.out.println("run...Thread");
        }
    }
     //3.对外提供方法改变标识
     public void stop(){
         this.flag = false;
    }
 }
 package com.kuang.state;
 //测试stop
 //1.建议线程正常停止-->利用次数,不建议死循环
 //2.建议使用标志位-->设置一个标志位
 //3.不要使用stop或者destroy等过时或者JDK不建议使用的方法
 public class TestStop implements Runnable{
 ​
     //1.设置一个标识位
     private boolean flag = true;
     @Override
     public void run(){
         int i = 0;
         while(flag){
             System.out.println("run....Thread" + i++);
        }
 ​
    }
     //2.设置一个公开的方法停止线程,转换标志位
     public void stop(){
         this.flag = false;
    }
 ​
     public static void main(String[] args) {
         TestStop testStop = new TestStop();
         
         new Thread(testStop).start();
         for (int i = 0; i < 1000; i++) {
             System.out.println("main" + i);
             if(i==900){
                 //调用stop方法切换标志位,让线程停止
                 testStop.stop();
                 System.out.println("线程该停止了");
            }
             
        }
 ​
    }
 }
 ​

线程休眠

sleep(时间)指定当前线程阻塞的毫秒数 1000ms = 1s

sleep存在异常InterruptedException;

sleep时间到达后线程进入就绪状态;

sleep可以模拟网络延时,倒计时等。

每个对象都有一个锁,sleep不会释放锁;

 package com.kuang.state;
 ​
 import com.kuang.demo01.TestThread4;
 ​
 //模拟网络延时:放大问题的发生性
 public class TestSleep implements Runnable{
     //票数
     private int ticketNums = 10;
 ​
     @Override
     public void run(){
         while(true){
             if (ticketNums<=0){
                 break;
            }
             //模拟延时
             try{
                 Thread.sleep(100);
            }catch (InterruptedException e){
                 e.printStackTrace();
            }
             System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"票");
 ​
        }
 ​
    }
 ​
     public static void main(String[] args) {
         TestThread4 ticket = new TestThread4();
 ​
         new Thread(ticket,"小明").start();
         new Thread(ticket,"老师").start();
         new Thread(ticket,"黄牛党").start();
    }
 }
 ​
 ​
 ​
模拟倒计时
 package com.kuang.state;
 //模拟倒计时
 public class TestSleep2 {
     public static void main(String[] args) {
         try {
             tenDown();
        } catch (InterruptedException e) {
             e.printStackTrace();
        }
 ​
    }
 //模拟倒计时
     public static void tenDown() throws InterruptedException {
         int num = 10;
 ​
         while (true){
             Thread.sleep(1000);
             System.out.println(num--);
             if (num<=0){
                 break;
            }
        }
    }
 }
 ​
模拟系统当前时间
 package com.kuang.state;
 ​
 import java.text.SimpleDateFormat;
 import java.util.Date;
 ​
 //模拟倒计时
 public class TestSleep2 {
     public static void main(String[] args) {
         //打印当前系统时间
         Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
 ​
         while(true){
             try {
                 Thread.sleep(1000);
                 System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                 startTime = new Date(System.currentTimeMillis());//更新当前时间
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
        }
 ​
    }
 //模拟倒计时
     public static void tenDown() throws InterruptedException {
         int num = 10;
 ​
         while (true){
             Thread.sleep(1000);
             System.out.println(num--);
             if (num<=0){
                 break;
            }
        }
    }
 }
 ​

线程礼让

礼让线程,让当前正在执行的线程暂停,但不阻塞

将线程从运行状态转为就绪状态

让cpu重写调度,礼让不一定成功!看CPU心情

 package com.kuang.state;
 ​
 public class TestYield {
     public static void main(String[] args) {
        MyYield myYield = new MyYield();
 ​
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
 ​
    }
 ​
 ​
 }
 class MyYield implements Runnable{
     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName()+"线程开始执行");
         Thread.yield();//礼让
         System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }
 }
 ​

线程强制执行 Join

Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

可以想象成插队

 package com.kuang.state;
 //测试join方法 想象为插队
 public class TestJoin implements Runnable{
     @Override
     public void run() {
         for (int i = 0; i < 1000; i++) {
             System.out.println("线程vip来了"+ i);
 ​
 ​
        }
 ​
    }
 ​
     public static void main(String[] args) throws InterruptedException {
 ​
         //启动我们的线程
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
 ​
        //主线程
         for (int i = 0; i < 500; i++) {
             if (i==200){
                 thread.join();//插队
            }
             System.out.println("main" + i);
 ​
        }
 ​
 ​
    }
 }
 ​

线程状态观测

Thread.State

线程状态。线程可以处于以下状态之一:

NEW

尚未启动的线程处于此状态

RUNNABLE

在Java虚拟机中执行的线程处于此状态

BLOCKED

被阻塞等待监视器锁定的线程处于此状态

WAITING

正在等待另外一个线程执行特定动作的线程处于此状态

TIMED WAITING

正在等待另一个线程执行动作达到指定等待时间的线程处于此状态

TERMINATED

已退出的线程处于此状态

一个线程可以在给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态

 package com.kuang.state;
 ​
 ​
 ​
 //观察测试线程的状态
 public class TestState {
     public static void main(String[] args) throws InterruptedException {
 ​
 ​
     Thread thread = new Thread(()->{
         for (int i = 0; i < 5; i++) {
             try {
                 Thread.sleep(1000);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
 ​
        }
         System.out.println("/////");
    });
     //观察状态
     Thread.State state = thread.getState();//alt+ 回车
         System.out.println(state);//NEW
 ​
         //观察启动后
         thread.start();//启动线程
         state = thread.getState();
         System.out.println(state);//Run
 ​
         while(state != Thread.State.TERMINATED){
             //只要线程不终止,就一直输出状态
             Thread.sleep(100);
             state = thread.getState();//更新线程状态
             System.out.println(state);//输出状态
             //死了的线程不能再次启动
 ​
        }
 ​
 ​
    }
 ​
 ​
 }
 ​

线程优先级

Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。

线程的优先级用数字表示,范围从1~10

 Thread.MIN_PRIORITY = 1;
 Thread.MAX_PRIORITY = 10;
 Thread.NORM_PRIORITY = 5;
 ​

使用以下方式改变或获取优先级

 getPriority().setPriority(int xxx)
线程优先级高不一定先执行
优先级的设定建议在start()调度前
优先级低只意味着获得调度的概率低,并不是优先级低的就不会被调用了。这都是看CPU的调度。
 package com.kuang.state;
 //测试线程优先级
 public class TestPriority {
     public static void main(String[] args) {
 ​
         //主线程默认优先级
         System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
         MyPriority myPriority = new MyPriority();
         Thread t1= new Thread(myPriority);
         Thread t2= new Thread(myPriority);
         Thread t3= new Thread(myPriority);
         Thread t4= new Thread(myPriority);
         Thread t5= new Thread(myPriority);
         Thread t6= new Thread(myPriority);
 ​
         //先设置优先级,再启动
         t1.start();
 ​
         t2.setPriority(1);
         t2.start();
 ​
         t3.setPriority(4);
         t3.start();
 ​
         t4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
         t4.start();
 ​
         t5.setPriority(8);
         t5.start();
 ​
         t6.setPriority(7);
         t6.start();
 ​
    }
 ​
 }
 class  MyPriority implements Runnable{
 ​
     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
 }

守护(daemon)线程

线程分为用户线程和守护线程

虚拟机必须确保用户线程执行完毕

虚拟机不用等待守护线程执行完毕

如:后台记录操作日记,监控内存,垃圾回收等待..

 package com.kuang.state;
 ​
 public class TestDaemon {
     public static void main(String[] args) {
         God god = new God();
         You you = new You();
         Thread thread = new Thread(god);
         thread.setDaemon(true);//默认是false表示用户线程,正常线程都是用户线程...
 ​
         thread.start();//上帝守护线程启动
         new Thread(you).start();//你 用户线程启动...
    }
 ​
 }
 //上帝
 class  God implements Runnable{
     @Override
     public void run() {
        while(true){
            System.out.println("自己保佑自己");
        }
    }
 }
 ​
 ​
 //你
 class You implements Runnable{
     @Override
     public void run(){
         for (int i = 0; i < 35000; i++) {
             System.out.println("你一生都开兴的活着");
        }
         System.out.println("======goodbye!world=======");//第一次学的是hello,world
 ​
    }
 }

03 线程同步

多个线程操作同一个资源

并发:同一个对象被多个线程同时操作

处理多线程问题时,多个线程访问同一个对象(并发),并且某些线程还想修改这个对象。这时我们就需要线程同步。线程同步其实就是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列,等待前面线程使用完毕,下个线程再使用

由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问的冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制(synchronized),当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可。存在以下问题:

一个线程持有锁会导致其他所有需要此锁的线程挂起;

在多个线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;

如果一个优先级高的线程等到一个优先级低的线程放锁,会导致优先级倒置,引起性能问题。

 package com.kuang.syn;
 //不安全的买票
 //线程不安全,有负数
 public class UnsafeBuyTicket {
     public static void main(String[] args) {
         BuyTicket station = new BuyTicket();
 ​
         new Thread(station,"小明").start();
         new Thread(station,"小红").start();
         new Thread(station,"黄牛党").start();
    }
 }
 ​
 ​
 class BuyTicket implements Runnable{
 ​
     //票
     private int ticketNums = 10;
     boolean flag = true;//外部停止方式
 ​
 ​
     @Override
     public void run(){
         //买票
         while (flag){
             try{
                 buy();
            }catch (InterruptedException e){
                 e.printStackTrace();
            }
        }
 ​
        }
 ​
 ​
     private void buy() throws InterruptedException {
         //判断是否有票
         if (ticketNums<=0){
             flag = false;
             return;
        }
         //模拟延时
         Thread.sleep(100);
 ​
 ​
         System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
 }
线程执行顺序随机,所以结果不一样
 package com.kuang.syn;
 //不安全取钱
 //两个人去银行取钱
 public class UnsafeBank {
     public static void main(String[] args) {
         //账户
         Account account = new Account(100,"结婚基金");
         Drawing you = new Drawing(account,50,"你");
         Drawing gf = new Drawing(account,100,"gf");
         you.start();
         gf.start();
    }
 }
 ​
 ​
 //账户
 class Account{
     int money;//余额
     String name;//卡名
 ​
     public Account(int money, String name) {
         this.money = money;
         this.name = name;
    }
 }
 ​
 //银行:模拟取款
 class Drawing extends Thread{
 ​
     Account account;//账户
     //取了多少钱
     int drawingMoney;
     //现在手里有多少钱
     int nowMoney;
 ​
     public Drawing(Account account,int drawingMoney,String name){
         super(name);
         this.account = account;
         this.drawingMoney = drawingMoney;
 ​
    }
 ​
     //取钱
     @Override
     public void run(){
         //判断有没有钱
         if (account.money - drawingMoney <0){
             System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
             return;
        }
         //sleep可以放大问题发生性
         try {
             Thread.sleep(1000);
        } catch (InterruptedException e) {
             e.printStackTrace();
        }
 ​
 ​
         //卡内余额 = 余额 - 你取走的钱
         account.money = account.money - drawingMoney;
         //你手里的钱
         nowMoney = nowMoney + drawingMoney;
 ​
         System.out.println(account.name + "余额为:" + account.money);
         //Thread.currentThread().getName() = this.getName()
         System.out.println(this.getName()+"手里的钱:" + nowMoney);
    }
 ​
 ​
 }
 package com.kuang.syn;
 ​
 import java.util.ArrayList;
 import java.util.List;
 ​
 //线程不安全集合
 public class UnselfList {
     public static void main(String[] args) {
         List<String> list = new ArrayList<String>();
         for (int i = 0; i < 10000; i++) {
             new Thread(()->{
                 list.add(Thread.currentThread().getName());
 ​
            }).start();
 ​
        }
         try {
             Thread.sleep(4000);
        } catch (InterruptedException e) {
             e.printStackTrace();
        }
         System.out.println(list.size());
 ​
    }
 }
 ​

同步方法

由于我们可以通过private关键字来保证数据对象只能被方法访问,所有我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronzied方法和synchronized块

 同步方法:public synchronized void method(int args){}

synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,知道该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行

缺陷:若将一个大的方法申明为synchronized将会影响效率

方法里面需要修改的内容才需要锁,锁的太多,浪费资源

同步块

同步块:synchronized(Obj){}

Obj称之为同步监视器

Obj可以是任何对象,但是推荐使用共享资源作为同步监视器

同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class

同步监视器的执行过程

1.第一个线程访问,锁定同步监视器,执行其中代码

2.第二个线程访问,发现同步监视器被锁定,无法访问

3.第一个线程访问完毕,解锁同步监视器

4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问

 package com.kuang.syn;
 //不安全取钱
 //两个人去银行取钱
 public class UnsafeBank {
     public static void main(String[] args) {
         //账户
         Account account = new Account(100,"结婚基金");
         Drawing you = new Drawing(account,50,"你");
         Drawing gf = new Drawing(account,100,"gf");
         you.start();
         gf.start();
    }
 }
 ​
 ​
 //账户
 class Account{
     int money;//余额
     String name;//卡名
 ​
     public Account(int money, String name) {
         this.money = money;
         this.name = name;
    }
 }
 ​
 //银行:模拟取款
 class Drawing extends Thread{
 ​
     Account account;//账户
     //取了多少钱
     int drawingMoney;
     //现在手里有多少钱
     int nowMoney;
 ​
     public Drawing(Account account,int drawingMoney,String name){
         super(name);
         this.account = account;
         this.drawingMoney = drawingMoney;
 ​
    }
 ​
     //取钱
     //synchronized默认锁的是this synchronized块可以锁任何对象
     //锁的对象是变化的量,只有存在银行的钱account在变化,需要增删改的对象
     @Override
     public  void run(){
 ​
         synchronized (account){
             //判断有没有钱
             if (account.money - drawingMoney <0){
                 System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                 return;
            }
             //sleep可以放大问题发生性
             try {
                 Thread.sleep(1000);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
 ​
 ​
             //卡内余额 = 余额 - 你取走的钱
             account.money = account.money - drawingMoney;
             //你手里的钱
             nowMoney = nowMoney + drawingMoney;
 ​
             System.out.println(account.name + "余额为:" + account.money);
             //Thread.currentThread().getName() = this.getName()
             System.out.println(this.getName()+"手里的钱:" + nowMoney);
        }
 ​
 ​
 ​
    }
 ​
 ​
 ​
 }
 package com.kuang.syn;
 //不安全的买票
 //线程不安全,有负数
 public class UnsafeBuyTicket {
     public static void main(String[] args) {
         BuyTicket station = new BuyTicket();
 ​
         new Thread(station,"小明").start();
         new Thread(station,"小红").start();
         new Thread(station,"黄牛党").start();
    }
 }
 ​
 ​
 class BuyTicket implements Runnable{
 ​
     //票
     private int ticketNums = 10;
     boolean flag = true;//外部停止方式
 ​
 ​
     @Override
     public void run(){
         //买票
         while (flag){
             try{
                 buy();
            }catch (InterruptedException e){
                 e.printStackTrace();
            }
        }
 ​
        }
 ​
         //synchronized 同步方法 ,实现了一个锁,会去拿对象的锁 buy方法的锁是BuyTicket,锁的是this
     private synchronized  void buy() throws InterruptedException {
         //判断是否有票
         if (ticketNums<=0){
             flag = false;
             return;
        }
         //模拟延时
         Thread.sleep(100);
 ​
 ​
         System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
 }
 package com.kuang.syn;
 ​
 import java.util.ArrayList;
 import java.util.List;
 ​
 //线程不安全集合
 public class UnselfList {
     public static void main(String[] args) {
         List<String> list = new ArrayList<String>();
         for (int i = 0; i < 10000; i++) {
             new Thread(()->{
                 synchronized (list){
                     list.add(Thread.currentThread().getName());
                }
            }).start();
 ​
        }
         try {
             Thread.sleep(4000);
        } catch (InterruptedException e) {
             e.printStackTrace();
        }
         System.out.println(list.size());
 ​
    }
 }
 ​

JUC安全类型的集合

 package com.kuang.syn;
 ​
 import java.util.concurrent.CopyOnWriteArrayList;
 ​
 //测试JUC安全类型的集合
 public class TestJUC {
     public static void main(String[] args) {
         //集合都加泛型
         CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
         for (int i = 0; i < 10000; i++) {
             new Thread(()->{
                 list.add(Thread.currentThread().getName());
            }).start();
        }
         try {
             Thread.sleep(3000);
        } catch (InterruptedException e) {
             e.printStackTrace();
        }
         System.out.println(list.size());
    }
 }
 ​
上一篇:sql语句分析


下一篇:如何安装Genymotion虚拟机以及Genmotion的eclipse插件