thread线程

1简介

1.正常的程序执行时纵向顺序执行。如果主线程调用了其他方法,则是在其他方法执行完成之后再回到主线程。

2.多线程执行,则是在主线程执行过程中新开一条线程执行其他方法,这个时候主线程和子线程并行交替执行。

3.Process程序跑起来就是一个进程,每一个进程包含多个线程thread

4.很多多线程都是模拟出来的,就是只有一个cpu交替执行不同的线程。并不是正真意义上的同时执行,只有多个cpu才能实现多线程。

2基本概念

1.线程就是独立的执行路径(每个线程自己执行,如main,gc).

2.在程序执行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程

3.main(),称之为主线程,为系统的入口,用于执行整个程序。

4.在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的。cpu调度执行,了解线程优先级的概念

5.对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。 必须了解的高并发问题

6.线程会带来额外的开销,如cpu调度事件,并发控制开销。就是为了让多个线程或程序同时执行,cpu会消耗时间。

7.每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。。。。。。。原子性

3线程创建

1.继承Thread类,实现Runnable接口,实现Callable接口

1.继承Thread


//这个是继承Thread类来实现多线程的方法
//线程开启后不一定立即执行,需要等待cpu调度决定什么时候执行
public class TestThread01 extends Thread{
    //重写run();
    @Override
    public void run(){
        for (int i = 0; i < 200; i++) {
            System.out.println("===我在执行多线程"+i);
        }
    }
    public static void main(String[] args) {
        TestThread01 testThread01= new TestThread01();
        //调用start()方法才会开启新的线程,
        //testThread01.start();
        //调用run()方法,只是普通调用方法,不会有新的线程
        testThread01.run();

        for (int i = 0; i < 200; i++) {
            System.out.println("===我在执行主方法"+i);
        }
    }
}

我的实际工作中,导入数据并持久化用到过多线程。主线程调用子线程,实现对数据的校验和持久化操作(有异常则抛出异常),主线程则返回数据给前端,表示数据已经上传成功。
    
    
一个简单的多线程下载图片的:通过继承Threa接口
    import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestThread2 extends  Thread{
    private String url; 
    private String name;

    //构造方法
   public  TestThread2(String url,String name ){
        this.url=url;
        this.name=name;
    };

    @Override
    public void run() {
        //新的线程调用的下载方法
    WebDownLoad webDownLoad = new WebDownLoad();
    webDownLoad.webDownLoad( url, name);
        System.out.println("下载图片出错了"+name);
    }

    public static void main(String[] args) {
        TestThread2 testThread2 = new TestThread2("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","first.png");
        TestThread2 testThread3 = new TestThread2("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","second.png");
        TestThread2 testThread4 = new TestThread2("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","third.png");
        testThread2.start();
        testThread3.start();
        testThread4.start();

    }

}
class WebDownLoad{

    public  void webDownLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File (name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载图片出错了"+Thread.currentThread());
        }

    }

}


2.实现Runnable接口,多用该方法比较灵活

通过实现Runnable接口,然后是静态代理的方式新建Thread调用start()
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class TestThread2 implements   Runnable{
    private String url;
    private String name;
   public  TestThread2(String url,String name ){
        this.url=url;
        this.name=name;
    };
    @Override
    public void run() {
    WebDownLoad webDownLoad = new WebDownLoad();
    webDownLoad.webDownLoad( url, name);
    }
    public static void main(String[] args) {
        TestThread2 testThread2 = new TestThread2("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","first.png");
        TestThread2 testThread3 = new TestThread2("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","second.png");
        TestThread2 testThread4 = new TestThread2("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","third.png");
        new Thread(testThread2).start();
        new Thread(testThread3).start();
        new Thread(testThread4).start();
    }

}
class WebDownLoad{

    public  void webDownLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File (name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载图片出错了");
        }

    }

}

2.1多各线程同时操作一个对象课程出现的并发问题。
public class ThreadRunnables implements Runnable{
    private  int ticket =10;
    @Override
    public void run() {
        while (true){
            if(ticket<=0){
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket-- +"张票");
        }
    }

    public static void main(String[] args) {
        ThreadRunnables threadRunnables = new ThreadRunnables();
        //多个线程同时对一个对象进行操作
        new  Thread(threadRunnables,"小哥").start();
        new  Thread(threadRunnables,"同学").start();
        new  Thread(threadRunnables,"小红").start();
        new  Thread(threadRunnables,"路边打印").start();
    }
}

多线程并发的明显结果:同时出现了相同的票号,而却居然有负数的票
    
    
    同学拿到了第10张票
路边打印拿到了第9张票
小红拿到了第9张票
小哥拿到了第10张票
同学拿到了第8张票
路边打印拿到了第7张票
小红拿到了第6张票
小哥拿到了第5张票
小哥拿到了第4张票
小红拿到了第4张票
路边打印拿到了第3张票
同学拿到了第2张票
路边打印拿到了第1张票
小红拿到了第-1张票
小哥拿到了第0张票
同学拿到了第0张票

2.2龟兔赛跑的多线程操作。对于多线程有了更深入的认识。

​ 启动多线程调用同一个Runnable对象。在这个时候,Runnable的属性参数是多个线程公用的,只要有一个线程发生了变化,其他线程也发生了变化。run()方法是每个线程单独执行了,用到的Runnable参数会存在并发问题,其他新的变量都是各自变化的。

public class Race implements  Runnable{
    private  String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if ( gameOver(i)){
                if(Thread.currentThread().getName().equals("兔子") && i/10==0){
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i);
        }
    };
	private  boolean gameOver(int step){
    if(step==100 && winner == null){
        winner = Thread.currentThread().getName();
        System.out.println(Thread.currentThread().getName()+"取得胜利");
        return  true;
    }else  if (step==100 && winner != null){
        System.out.println(Thread.currentThread().getName()+"也结束了比晒");
        return  true;
    }{
        return false
                ;
    }
}
    public static void main(String[] args) {
        Race race=new Race();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

3实现Callable接口

​ 1.实现Callable接口,需要返回值类型

​ 2.重写call方法,需要抛出异常

​ 3.创建目标对象

​ 4.创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);

​ 5.提交执行:Future result1 = ser.submit(t1);

​ 6.获取结果:boolean r1 = result1.get();

​ 7.关闭服务:set.shutdownNow();

3.1实现callable接口,多线程下载图片(改造自实现Runnable接口)


public class ThreadCallable implements Callable<Boolean> {
    private String url;
    private String name;
    public  ThreadCallable(String url,String name ){
        this.url=url;
        this.name=name;
    };
    @Override
    public Boolean call() throws Exception {
        WebDownLoad webDownLoad = new WebDownLoad();
        webDownLoad.webDownLoad( url, name);
        return true;
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadCallable testThread2 = new ThreadCallable("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","first.png");
        ThreadCallable testThread3 = new ThreadCallable("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","second.png");
        ThreadCallable testThread4 = new ThreadCallable("https://www.kuangstudy.com/assert/images/index_topleft_logo_black.png","third.png");
       //创建服务
        ExecutorService ser= Executors.newFixedThreadPool(3);3为连接数量
        //提交执行
        Future<Boolean> r1 = ser.submit(testThread2);
        Future<Boolean> r2 = ser.submit(testThread3);
        Future<Boolean> r3 = ser.submit(testThread4);
        //获取结果
        boolean re1 = r1.get();
        boolean re2 = r2.get();
        boolean re3 = r3.get();
        ser.shutdownNow();  //关闭服务
    }
}
class WebDownLoad{

    public  void webDownLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载图片出错了");
        }

    }

}

4 Thread类实现了Runnable接口

​ 在我们通过实现Runnable接口的方法来实现多线程,最后通过new Thread(Runnable ru).start()方法来开启新的线程,启动run()方法的时候,用了静态代理的模式。Thread其实就是那个代理类。

4Lambda表达式

  1. 理解Function Interface 函数式接口是学习java8 lambda表达式的关键

  2. 函数式接口的定义:

    ​ 1.对于任何一个接口,如果只包含一个抽象方法,那么它就可以称之为函数式接口

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

以下是从一个函数式接口和实现类到lambda表达式的形成过程(必须是函数式接口)
    1.一般类实现接口
    2.静态内部类实现
    3.局部内部类实现
    4.匿名内部类实现
    5.lambda表达式
package lambda;

public class TestLambda {

    //类里的类静态内部类
     static class ILike2 implements  Like{
        @Override
        public void lambada() {
            System.out.println("i like labmda2");
        }

    }
    public static void main(String[] args) {
        Like like=new ILike();
        like.lambada();

      like=new ILike2();
        like.lambada();
        //局部内部类
        class ILike3 implements  Like{
            @Override
            public void lambada() {
                System.out.println("i like labmda3");
            }

        }
        like = new ILike3();
        like.lambada();

        //匿名内部类。只有接口对象
        like  = new Like(){
            @Override
            public void lambada() {
                System.out.println("i like labmda4");
            }
        };
        like.lambada();
        like = ()-> {
            System.out.println("i like labmda5");
        };
        like.lambada();

        Show show = ()->{
            System.out.println("i show");
        };
        show.showMe();
    }


}


interface Like{
    void  lambada();
}

class ILike implements  Like{
    @Override
    public void lambada() {
        System.out.println("i like labmda1");
    }

}

interface Show{
    void showMe();
}

interface ILove{
    void MyLove(String name,int age)
}
//带有参数的lambda表达式
ILove ilove = (name,age)->{
    System.out.pring(name+"小哥:"+age);
}

5线程的状态

6线程常用的方法

1.setPriority(int newPriority);更改线程优先级

2.static void sleep(long mills);指定毫秒时间内休眠,结束后就绪

3.void join(); 插队,等待该线程终止?????

4.static void yield() ;暂停当前正在执行的线程,并执行其他线程

5.void interrupt(); 中断线程,别用这个方法!!!

6.Boolean isAlive(); 测试线程是否在存活状态。

6.1 线程的终止


package TestThread;

import sun.awt.windows.ThemeReader;
//测试stop
//1.建议线程正常停止,---》利用次数,不建议死循环
//2.建议使用标志位,---》设立一个线程停止的标志
//3.不要使用stop,destory等过时的或者jdk不建议使用的方法
public class TestStop implements Runnable{
    //设立一个停止的标记
    private  boolean flag =true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("子线程在执行"+i++);
        }
       /* try {
            Thread.sleep(3000);
            System.out.println("子线程在执行"+flag);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        System.out.println("子线程在执行>>>"+Thread.currentThread().isAlive());

    }
    //写一个公开的方法停止线程。就是让子线程的程序结束
    public void stop(){
        this.flag=false;
    };
    public static void main(String[] args) {
        TestStop stop = new TestStop();
        new Thread(stop,"自线程").start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程执行"+i);
            if(i==89){
                stop.stop();
            }
        }
    }
}

6.2 线程休眠

一般用于模拟网络延时或者倒计时

​ 6.2.1 sleep是指当前线程阻塞的毫秒数

​ 6.2.2 sleep存在异常InterruptedException

​ 6.2.3sleep时间到达后,线程进入就绪状态

​ 6.2.4可以用于模拟网络延时或者倒计时。。。

​ 6.2.5没一个对象都有一个锁,sleep不会释放锁。


public class TestSleep {


    public static void main(String[] args) throws InterruptedException {
        /*for (int i = 0; i < 10; i++) {
            System.out.println(i);
            Thread.sleep(1000);
        }*/
        Date date = new Date(System.currentTimeMillis());
        while (true){
          Thread.sleep(1000);//线程休眠一秒钟
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
             date = new Date(System.currentTimeMillis());
        }
    }
}

6.3线程礼让

​ 这个比较简单,就是在代码中调用以下方法:: Thread.yeild();

6.4线程join

在一个线程执行过程中,另外一个线程join进来,cpu会优先执行这个线程,在这个线程执行结束后再回来

1.当两个线程在执行,jion的线程执行完之后,被插入的线程就绪
2.如果多个线程在执行,被jion的线程阻塞,其他线程正常的就绪状态



public class TestJoin implements  Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin,"VIP");
        TestJoin testJoin1 = new TestJoin();
        Thread thread1 = new Thread(testJoin1,"普通用户");
        thread.start();
        thread1.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("主线程在跑"+i);
            if(i==100){
                thread.join();
            }
        }

    }
}

6.5线程状态获取thread.getState();

​ 1.新生 2.就绪 3.阻塞 4.运行 5.死亡

​ 1.Thread t = new Thread();线程对象一旦创建就进入新生状态。

Thread.State state=  thread.getState(); NEW  state是枚举值

​ 2.就绪 t.start();,调用start后,线程进入就绪状态,但是不一定立即执行,RUNNABKLE

​ 3.阻塞,当调用sleep,wait或同步锁时,线程进入阻塞状态。代码不往下执行,阻塞解除后,重新进入就绪状态,等待CPU分配。 BLOCKED

​ 4.进入运行状态的线程才正在执行程序代码

​ 5.线程中断或者结束,一旦进入死亡状态不可以再次启动。 TERMINATED

6.6 线程优先级

​ 优先级范围1-10,最小为1,组大为10,设置其他数值则抛异常。

​ 必须先设置优先级再启动线程才会有效。

Thread.MAX_PRIORITY  最大为10
Thread.NORM_PRIORITY	默认为5
Thread.MIN _PRIORITY  最小为1,
 thread1.setPriority(1);
 thread1.start();

Thread.currentThread().getPriority() 获得当前线程的优先级

6.7守护线程 thread.setDaemon

1.线程分为守护线程和用户线程
2.我们正常建立的线程都是用户线程
3.虚拟机必须确保用户线程执行完毕
4.虚拟机不用等待守护线程执行完毕
5.守护线程:如后台记录操作日志,监控内存,垃圾回收等
    thread.setDaemon(true);设置为守护线程
package TestThread;
public class TestDaemon {
    public static void main(String[] args) {
        God god =new God();
        Thread thread = new Thread(god);
        thread.setDaemon(true);
        thread.start();
        new Thread(new You()).start();
    }

}
class God implements  Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("s" +
                    "上帝在守护你");
        }
    }
}
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("我快乐的或者!!");
        }
    }
}

7不安全的多线程

7.1 多线程买票

7.2 多线程取钱

7.3ArrayList<>()

8同步方法同步块

8.1同步方法

同步方法,及在方法前加 synchronized:  public synchronized void method(args[]){};

    //同步方法,保证线程安全,这里锁的时当前方法所在的类对象。
    public synchronized void  buyticket() throws InterruptedException {
        //判断是否有票
        if(ticketNum<=0){
            System.out.println("票卖光了");
            flag=false;
            return;
        }
        //模拟延时
        Thread.sleep(100);
        //买票
        System.out.println(Thread.currentThread().getName()+"购买了第"+ticketNum--+"张票");
    }

8.2同步块

同步块,即在一端代码前加上锁 synchronized(obj){};

obj是锁的对象,{}是代码块,只有获取了obj的对锁才能执行代码块里的代码
    
    {
        synchronized(account){//被锁的是取钱的账户。
            if(account.getMoney()<dmoney){
                System.out.println("钱不够了!!!");
                return;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.setMoney(account.getMoney()-dmoney);
System.out.println(account.getMoney());
        }


    }

8.3一个安全的list

CopyOnWriteArrayList  是一个线程安全的集合

{
        CopyOnWriteArrayList<String> copyOnWriteArrayList =new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                copyOnWriteArrayList.add(Thread.currentThread().getName());
            }).start();

        }
Thread.sleep(2000);
        System.out.println(copyOnWriteArrayList.size());
    }

8.4死锁

​ 产生死锁的四个必要条件:

​ 1.一个资源一次只能被一个进程私用。

​ 2.请求与保持条件:一个进程因请求资源阻塞时,对已获得的资源保持不放

​ 3.不剥夺条件:进程已获得的资源,在未使用完之前不能强行剥夺

​ 4.循环等条件:若干进程之间形成循环等资源的关系


public class TestDeadLock {
    public static void main(String[] args) {
        new Thread(new MakeUp(0,"韩晓晓")).start();
        new Thread(new MakeUp(2,"韩大大")).start();
    }
}
class Mirror{
}
class LipTick{

}

class MakeUp extends  Thread{

    static  Mirror mirror =new Mirror();
    static  LipTick lipTick = new LipTick();
    int nu;
    String name;
    public MakeUp(int nu, String name ){
        this.name=name;
        this.nu=nu;
    }
    @Override
    public void run() {
       if(nu==0){
           synchronized (mirror){
               System.out.println(name+"拿到了镜子");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }

           synchronized (lipTick){
               System.out.println(name+"拿到了口红");

           }
       }else{
           {
               synchronized (lipTick){
                   System.out.println(name+"拿到了口红");
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
               synchronized (mirror){
                   System.out.println(name+"拿到了镜子");

               }
           }

       }

    }


8.5 LOCK显式锁

1.定义一个锁 private  final ReentrantLock lock = new ReentrantLock();
2.听过try{}形式,锁定一个代码块,lock.lock  和lock.unlock

class BuyTicket implements    Runnable{
    private int  num =10;

    private  final ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
while (true){
           try {
lock.lock();
               if (num > 0) {
                   try {
                       Thread.sleep(1000);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread().getName() + num--);
               } else {
                   break;
               } ;
           }finally {
               lock.unlock();
           }

    }
}}

9管程法

生产者生产产品放入缓存区,消费者从缓冲区取产品。
//生产者,消费者模型,利用缓冲区----管程法让两个线程关联
//生产者,消费者,产品,缓冲区
public class TestPc {
    public static void main(String[] args) {
        SynContainer synContainer =new SynContainer();
        new Product(synContainer).start();
        new Customer(synContainer).start();

    }
}
产品
class Chicken{
    public   int id;
    public Chicken(int id){
        this.id=id;
    };
}
缓冲区
class SynContainer{
    Chicken[] cs = new Chicken[10];
    int count=0;
    public  synchronized void push(Chicken chicken) throws InterruptedException {
        if(count == cs.length){
            this.wait();
        }
        System.out.println("前台来了一只鸡"+chicken.id);
        cs[count]=chicken;
        count++;
        this.notifyAll();
    }
    public synchronized Chicken pop() {
        if(count<=0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        count--;
        Chicken chicken = cs[count];
        System.err.println("消费着消费一只鸡"+chicken.id);

           this.notifyAll();

            return chicken;
    }

}
消费者
class Customer extends Thread{

    SynContainer synContainer;

    public Customer(SynContainer synContainer){
        this.synContainer=synContainer;
    }
    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            try {
                Thread.sleep(500);
                synContainer.pop();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }
}
生产者
class Product extends Thread{
    SynContainer synContainer;
    public Product(SynContainer synContainer){
        this.synContainer=synContainer;
    }
    @Override
    public void run() {
        for (int i1 = 0; i1 < 100; i1++) {
            try {
                Thread.sleep(200);
                Chicken chicken =new Chicken(i1);
                synContainer.push(chicken);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


10信号等法

通过一各标记,控制两个线程的等待或者开启
    
    
    package TestThread;

public class TestPC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Watcher(tv).start();  new Player(tv).start();

    }

}

//生产者
class Player extends Thread{

    TV tv;
    public Player (TV tv){
        this.tv=tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==0){
                tv.payer("一首歌春天的故事");
            }else {
                tv.payer("表演了电视据红玫瑰");
            }
        }

    }
}
//消费者
class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv=tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            tv.watcher();
        }
    }
}

//产品
class TV {
    String voice;
    //开关
    boolean flag = true;

    public synchronized void payer(String voice){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.voice=voice;
        System.out.println("演员表演:"+voice);
        flag = !this.flag;
        this.notifyAll();

    }

    public synchronized void watcher(){
        if (flag ){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看表演:"+voice);
        flag=!flag;
        this.notifyAll();
    }
}

11线程池

public class TestThreadPools {
    public static void main(String[] args) {
        //生成一个有两个线程的池
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new threads());//开启线程服务
        service.execute(new threads());
        service.execute(new threads());
        service.execute(new th());
        service.execute(new th());
        service.execute(new th());
        //关闭线程
        service.shutdown();
    }
}
class threads implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

class th extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"Run");
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值