首页 > 编程语言 > 详细

多线程基础

时间:2021-02-19 23:56:25      阅读:49      评论:0      收藏:0      [点我收藏+]

多线程

java.Thread

线程简介

  1. 多任务

    同时做多件事

  2. 多线程

    多条车道同时运行,解决问题

  3. 程序、进程、线程

    进程:是程序的一次执行过程

    线程是独立的执行路径

    一个进程中可以包含多个线程

    main(主线程)

  4. Process 、Thread

    真正的多线程是多个CPU

    模拟多线程,一个cpu,在一个时间点,只能执行一个代码,切换块,所以有个同时执行的感觉

注意:对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制(排队)

线程实现(重点)

三种创建方式

Thread class(重点)

步骤:

  1. 创建线程,继承Thread
  2. 重写run()方法
  3. 调用start()方法开启线程
package com.thread.demo1;

//创建线程1:继承Thread类, 重写run方法,调用start开启线程

//线程开启后不一定立即执行,由cpu分配
public class TestThread1 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    public static void main(String[] args) {
        //main线程

        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();

        //调用start()方法开启线程
        testThread1.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程  "+i);
        }
    }
}

Thread下载图片举例

package com.thread.demo2;

import org.apache.commons.io.FileUtils;

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

//练习Thread,实现多线程同步下载图片
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() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, name);
        System.out.println("下载了文件: " +name);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img-blog.csdnimg.cn/img_convert/6749870a78a275af1d438f266fa42f49.png","1.png");
        TestThread2 t2 = new TestThread2("https://img-blog.csdnimg.cn/img_convert/20296cd81a0863410248039e3e02f514.png","2.png");
        TestThread2 t3 = new TestThread2("https://img-blog.csdnimg.cn/img_convert/628bdeb4e401ac8f602da8ab4391c94c.png","3.png");

        t1.start();
        t2.start();
        t3.start();
    }
}

class WebDownloader{
    //下载方法
    public void downloader(String url, String name){
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (MalformedURLException e) {
            e.printStackTrace();
            System.out.println("URL问题,Downloader出现问题");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,Downloader出现问题");
        }
    }
}

Runnable接口()重点

方便多个线程在一个对象中处理

线程启动方式:传入目标对象+Thread对象.strat();

package com.thread.demo3;

//创建线程方式3, 实现Runnable接口
public class TestRunnable implements Runnable{
    @Override
    public void run() {
        //runnable方法实例
        for (int i = 0; i < 20; i++) {
            System.out.println("线程"+ i);
        }
    }

    public static void main(String[] args) {
        //创建实现类对象
        TestRunnable testRunnable = new TestRunnable();
        //创建代理类对象
        new Thread(testRunnable).start();
        //Thread thread = new Thread(testRunnable);
        //启动线程
        //thread.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("主线程 " + i);
        }
    }

}

龟兔赛跑例子

package com.thread.demo6;
/*
龟兔赛跑
1、赛道距离,离重点越来越近
2、判断比赛是否结束
3、打印出胜利者
4、乌龟是赢,需模拟兔子睡觉
 */
public class GuiTuRace implements Runnable{
    private static String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            //模拟兔子睡觉
            if (Thread.currentThread().getName() == "兔子" && i % 10 == 0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //判断比赛是否结束
            boolean flag = gameOver(i);
            if (flag){
                break;
            }

            System.out.println(Thread.currentThread().getName() + " 跑了 " + i + " 步");
        }
    }

    public boolean gameOver(int steps){
        //判断是否有胜利者
        if (winner != null){//已经决出胜负
            return true;
        }{
            if (steps >= 100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is " + winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        GuiTuRace race = new GuiTuRace();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

callable(了解)

静态代理模式

Lamda表达式

new Thread(()-> System.out.println("我稀罕你")).start();

函数式接口

一个接口对应一个方法

举个例子:

package com.thread.demo8;
/*
lambda推导
 */
public class TestLambda1 {
    //3、静态内部类
    static class Like2 implements ILike{

        @Override
        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike iLike = new Like();
        iLike.lambda();

        iLike = new Like2();
        iLike.lambda();

        //4、局部内部类
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("I like lanbda3");
            }
        }

        iLike = new Like3();
        iLike.lambda();

        //5、匿名内部类,没有类的名称,必须借助接口或父类
        iLike = new ILike() {
            @Override
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        iLike.lambda();

        //用lambda简化
        ILike iLike1 = ()-> System.out.println("I like lambda5~~~~~");
        iLike1.lambda();
    }
}

//1、定义一个接口
interface ILike{
    void lambda();
}
//2、实现类
class Like implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like lambda");
    }
}

Lambda目的:简化函数式接口的实现方法;

广泛性用于Runnable中

线程状态

创建状态

new

就绪状态

start

运行状态

阻塞状态

sleep、wait、同步锁

每个线程都有一把锁,sleep不会释放锁

package com.thread.demo9;
/*
1000ms = 1s
sleep可以模拟网络延时、倒计时
 */

import com.thread.demo5.TestThread5;

//1、模拟网络延时:放大问题的发生性
public class TestSleep implements Runnable{
    //票数
    private int ticketNums = 10;
    @Override
    public void run() {
        while (true) {
            if (ticketNums < 1) {
                break;
            }
            //模拟延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " -->买到了第 " + ticketNums-- + " 张票");
        }
    }

    public static void main(String[] args) {
        TestThread5 t1 = new TestThread5();
        new Thread(t1, "梁蒸胤").start();
        new Thread(t1, "小张").start();
        new Thread(t1, "黄牛").start();
    }
}

package com.thread.demo9;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2 {
    public static void main(String[] args) throws InterruptedException {
        TestSleep2 testSleep2 = new TestSleep2();
        testSleep2.tenDown();

        //打印当前系统时间
        Date stat = new Date(System.currentTimeMillis());
        while (true){
            Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(stat));
            stat = new Date(System.currentTimeMillis());
        }
    }

    public void tenDown() throws InterruptedException {
        int num = 10;

        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num < 0) {
                break;
            }
        }
    }
}
package com.thread.demo9;
//测试礼让,不一定礼让成功,看CPU状态
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()+"线程开始执行");
        Thread.yield(); //礼让
        System.out.println(Thread.currentThread()+"线程停止执行");
    }
}
package com.thread.demo9;

//测试join, 想象为插位
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("VIP来了");
        }
    }

    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);
        }
    }
}

dead状态

终端、结束

package com.thread.demo9;

import com.liang.www.Test;

/*
测试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("mian "+ i);
            if (i == 900){
                testStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}
package com.thread.demo9;
//观察测试线程的状态
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(10000);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            System.out.println("///////");
        });

        //观察状态启动前
        Thread.State state = thread.getState();
        System.out.println(state);

        //观察启动后
        thread.start();
        state = thread.getState();
        System.out.println(state);

        while (state != Thread.State.TERMINATED){
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);
        }
    }
}

设置线程优先级——setPriority

package com.thread.demo9;
//测试线程的优先级
//优先级只是概率
public class TestPriority {
    public static void main(String[] args) {
        //主线程默认优先级
        System.out.println(Thread.currentThread().getName() +" -->" +Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();

        Thread thread1 = new Thread(myPriority);
        Thread thread2 = new Thread(myPriority);
        Thread thread3 = new Thread(myPriority);
        Thread thread4 = new Thread(myPriority);
        Thread thread5 = new Thread(myPriority);
        Thread thread6 = new Thread(myPriority);

        //先设置优先级再启动
        thread2.setPriority(1);
        thread3.setPriority(4);
        thread4.setPriority(Thread.MAX_PRIORITY);
        thread5.setPriority(8);
        thread6.setPriority(7);

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
        thread6.start();
    }
}

class MyPriority implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + Thread.currentThread().getPriority() + " "+ i);
        }
    }
}

守护线程——daemon

  • 线程分为用户线程和守护线程,用户线程结束,守护停止
package com.thread.demo9;

//测试守护线程
//上帝守护你
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);

        thread.start();

        new Thread(you).start();

    }
}

class God implements Runnable{
    public void run(){
        while (true){
            System.out.println("上帝保护着你");
        }
    }
}

class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("你一直都开心的活着");
        }
        System.out.println("goodbye!========");
    }
}

线程同步(重点)

并发:多个用户操作同一个资源

上万人同时抢100张票

  • 队列:代替排队
  • 锁:synchronized
  • 队列+锁保证线程同步的安全性

获得安全,损失性能,引起性能倒置

三大不安全案例

package com.thread.syn;

public class UnSafeBuyTackets {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();

        new Thread(buyTicket, "彭伟程").start();
        new Thread(buyTicket, "黄牛").start();
        new Thread(buyTicket,"大笨猪").start();
    }

}

class BuyTicket implements Runnable{
    //票
    private int ticketNumbers = 10;
    boolean flag = true;

    @Override
    public void run() {
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        //判断是否有票
        if (ticketNumbers <= 0){
            return;
        }
        //模拟延迟
        Thread.sleep(100);

        //买票
        System.out.println(Thread.currentThread().getName()+" 拿到 " + ticketNumbers--);
    }
}
package com.thread.syn;
//不安全取钱
//两个人取取钱
public class UnSafeBank {
    public static void main(String[] args) {
        //账户
        Account account = new Account(100, "结婚基金");

        Drawing you = new Drawing(account,50,"你");
        Drawing girlFriend = new Drawing(account,100,"girlFriend");

        you.start();
        girlFriend.start();
    }
}

class Account{
    private int money;
    private String name;

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

//银行:模拟取款
class Drawing extends Thread{
    Account account;  //zhanghu
    //取了多少钱
    private int drawingMoney;

    private int haveMoney;

    public Drawing(Account account,int drawingMoney, String name){
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        //判断有无钱
        if (account.getMoney() - drawingMoney < 0){
            System.out.println(Thread.currentThread().getName()+"余额不够,取不了");
            return;
        }
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        //卡内余额 = 余额 - 取的钱
        account.setMoney(account.getMoney() - drawingMoney);

        //你手里的钱
        haveMoney = haveMoney + drawingMoney;

        System.out.println(account.getName() + "余额为:" + account.getMoney());
        //Thread.currentThread().getName() = this.getName();
        System.out.println(this.getName()+"手里的钱"+haveMoney);
    }
}
package com.thread.syn;

import java.util.ArrayList;
import java.util.List;

//线程不安全的集合
public class UnSafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 20000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(30000);
        System.out.println(list.size());
    }
}

同步

//synchronized变为同步方法,锁的是this
    private synchronized void buy() throws InterruptedException {
        //判断是否有票
        if (ticketNumbers <= 0){
            return;
        }
        //模拟延迟
        Thread.sleep(100);

        //买票
        System.out.println(Thread.currentThread().getName()+" 拿到 " + ticketNumbers--);
    }
public void run() {
        //锁的对象是变换的量,增,删,改
        synchronized (account){
            //判断有无钱
            if (account.getMoney() - drawingMoney < 0){
                System.out.println(Thread.currentThread().getName()+"余额不够,取不了");
                return;
            }
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            //卡内余额 = 余额 - 取的钱
            account.setMoney(account.getMoney() - drawingMoney);

            //你手里的钱
            haveMoney = haveMoney + drawingMoney;

            System.out.println(account.getName() + "余额为:" + account.getMoney());
            //Thread.currentThread().getName() = this.getName();
            System.out.println(this.getName()+"手里的钱"+haveMoney);
        }
public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 2000; i++) {
            new Thread(()->{
                synchronized (list){
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        Thread.sleep(30000);
        System.out.println(list.size());
    }

死锁

package com.thread.syn;

//死锁:多个线程互相抱着对方需要的资源,然后形成僵持
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0,"灰姑娘");
        Makeup g2 = new Makeup(1,"白雪公主");

        g1.start();
        g2.start();
    }
}
//口红
class Lipstick{

}
//镜子
class Mirror{

}

class Makeup extends Thread{
    //需要的资源只有一份,用static来保证
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    int choice;//选择
    String girlName;  //化妆品使用者

    Makeup(int choice, String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        //化妆
        try {
            this.makeUp();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //化妆,互相持有对方的锁,就是需要拿到对方的资源
    private void makeUp() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {
                System.out.println(this.girlName + " 获得口红的锁");
                Thread.sleep(1000);
                synchronized (mirror) {
                    System.out.println(this.girlName + " 获得镜子的锁");
                }
            }
        } else {
            synchronized (mirror) {
                System.out.println(this.girlName + " 获得镜子的锁");
                Thread.sleep(1000);
                synchronized (lipstick) {
                    System.out.println(this.girlName + " 获得口红的锁");
                }
            }
        }
    }
}

产生死锁的四个必要条件

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源儿阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

避免死锁

只需想方法破解其中任意一个或多个条件就可避免死锁发生

    //化妆,互相持有对方的锁,就是需要拿到对方的资源
    private void makeUp() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {
                System.out.println(this.girlName + " 获得口红的锁");
                Thread.sleep(1000);
            }
            synchronized (mirror) {
                System.out.println(this.girlName + " 获得镜子的锁");
            }
        } else {
            synchronized (mirror) {
                System.out.println(this.girlName + " 获得镜子的锁");
                Thread.sleep(1000);
            }
            synchronized (lipstick) {
                System.out.println(this.girlName + " 获得口红的锁");
            }
        }
    }

Lock锁

可重入锁

class A{
    private final ReentrantLock lock = new ReentrantLock();
    public void m(){
        lock.lock();
        try {
            //保证线程安全的代码
        }
        finally {
            lock.unlock();
            //如果同步代码有异常,要将unlock()写入finallt语句块
        }
    }
}

Lock 与 synchronized 区别

  • Lock时显示锁(手动开启和关闭), synchronized是隐式锁,出了作用域自动释放
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • Lock锁,jvm将花费较少的时间来调度线程,性能更好
  • 优先使用顺序:Lock > 同步代码块 > 同步方法

线程通信

生产者消费者问题

生产者负责生产,消费者负责消费,两者通过第三者通信

管程法

package com.thread.gaoji;

//测试:生产者消费者模型——利用缓冲区解决:管程法

//生产者  消费者 产品 缓冲区
public class TestPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();

        new Producter(container).start();
        new Consumer(container).start();
    }
}

//生产者
class Producter extends Thread{
    SynContainer container;
    public Producter(SynContainer container){
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了"+ i + "号鸡");
            container.push(new Chicken(i));
        }
    }
}

//消费者
class Consumer extends Thread{
    SynContainer container;
    public Consumer(SynContainer container){
        this.container = container;
    }
    //消费

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了--> " + container.pop().id+"号鸡");
        }
    }
}

//产品
class Chicken extends Thread{
    int id;

    public Chicken(int id) {
        this.id = id;
    }
}
//缓冲区
class SynContainer{
    //需要一个容器大小
    Chicken[] chickens = new Chicken[10];
    //容器计数器
    int count = 0;
    //生产者放入产品
    public synchronized void push(Chicken chicken){
        //如果容器满了,就需要等待消费者消费
        if (count == chickens.length){
            //通知消费,生产等待
            try {
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //如果没有满,就需要丢入产品
        chickens[count] = chicken;
        count++;

        //可以通知消费者消费了
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Chicken pop(){
        //判断能否消费
        if (count == 0){
            //等待生产
            try{
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chicken chicken = chickens[count];

        //吃完了,通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

信号灯法-flag

package com.thread.gaoji;
//测试生产者消费者问题:信号灯法,标志位解决
public class TestPC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//生产者  演员
class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i%2 == 0){
                try {
                    this.tv.play("快乐大本营");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else {
                try {
                    this.tv.play("抖音:记录美好生活");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//消费者  观众
class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}
//产品  节目
class TV{
    //演员表演,观众等待
    //观众观看,演员等待
    String voice;  //表演的节目
    boolean flag = true;
    //表演
    public synchronized void play(String voice) throws InterruptedException {
        if (!flag){
            this.wait();
        }

        System.out.println("演员表演了:" + voice);
        //通知观众观看
        this.notifyAll();
        this.voice = voice;
        this.flag = !this.flag;
    }

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

高级主题

  • 经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大
  • 解决方法:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可比米娜频繁创建和销毁,实现重复利用

使用线程池

package com.thread.gaoji;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//测试线程池
public class TestPool {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        //newFixedThreadPool线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);

        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //2.关闭链接
        service.shutdown();
    }
}

class MyThread implements Runnable{
    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());
    }
}

多线程基础

原文:https://www.cnblogs.com/liangzynb/p/14417377.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!