多线程

程序、进程、线程

程序

程序是指令和数据的有序集合,是一个静态的概念

进程(process)

进程是程序的一次执行过程,是动态的概念,是系统资源分配的单位

线程(Thread)

通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,线程是CPU调度和执行的单位

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

线程三种创建方式

继承Thread类

package com.henry.thread;
//继承Thread类,重写run方法,调用start开启线程
public class TestThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("x+"+i);
        }
    }

    public static void main(String[] args) {
        //创建一个线程对象
        TestThread testThread = new TestThread();
        //调用start方法开启线程,调用run方法不会并行执行,会顺序执行 
        testThread.start();
        //main线程,主线程
        for (int i = 0; i < 1000 ; i++) {
            System.out.println("y+"+i);
        }
    }
}

多线程下载图片

package com.henry.thread;

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 filename;

    public TestThread2(String url, String filename) {
        this.url = url;
        this.filename = filename;
    }

    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,filename);
        System.out.println("下载了文件名为:"+filename);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829165338623-1016877944.png","1.png");
        TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829170405010-1982825617.png","2.png");
        TestThread2 t3 = new TestThread2("https://pic.cnblogs.com/avatar/2035046/20200511235307.png","3.png");
        t1.start();
        t2.start();
        t3.start();
        //下载了文件名为:2.png
        //下载了文件名为:1.png
        //下载了文件名为:3.png
    }
}


class WebDownloader{
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实现Runnable接口

package com.henry.thread;

//创建线程方式2:实现runnable接口,重写run方法,执行线程需要runnable接口实现类
public class TestThread3 implements Runnable{
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("x+"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();
        //创建线程对象,通过线程对象开启我们的线程
        
        new Thread(testThread3).start();
        for (int i = 0; i < 1000 ; i++) {
            System.out.println("y+"+i);
        }
    }
}

多线程下载图片

package com.henry.thread;

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 filename;

    public TestThread2(String url, String filename) {
        this.url = url;
        this.filename = filename;
    }

    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,filename);
        System.out.println("下载了文件名为:"+filename);
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829165338623-1016877944.png","1.png");
        TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829170405010-1982825617.png","2.png");
        TestThread2 t3 = new TestThread2("https://pic.cnblogs.com/avatar/2035046/20200511235307.png","3.png");
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
        //下载了文件名为:2.png
        //下载了文件名为:1.png
        //下载了文件名为:3.png
    }
}



class WebDownloader{
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实现Callable接口

package com.henry.thread;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class TestThread2 implements Callable<Boolean> {
    private String url;
    private String filename;

    public TestThread2(String url, String filename) {
        this.url = url;
        this.filename = filename;
    }

    public Boolean call() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,filename);
        System.out.println("下载了文件名为:"+filename);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestThread2 t1 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829165338623-1016877944.png","1.png");
        TestThread2 t2 = new TestThread2("https://img2020.cnblogs.com/blog/2035046/202008/2035046-20200829170405010-1982825617.png","2.png");
        TestThread2 t3 = new TestThread2("https://pic.cnblogs.com/avatar/2035046/20200511235307.png","3.png");

        //创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(3);
        //提交执行
        Future<Boolean> r1 = service.submit(t1);
        Future<Boolean> r2 = service.submit(t2);
        Future<Boolean> r3 = service.submit(t3);
        //获取结果
        Boolean rb1 = r1.get();
        Boolean rb2 = r2.get();
        Boolean rb3 = r3.get();
        //关闭服务
        service.shutdownNow();
    }
}



class WebDownloader{
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

龟兔赛跑问题

package com.henry.thread;

public class Race implements Runnable{
    private String winner;
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if(Thread.currentThread().getName().equals("兔子") && i%10==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            boolean flag = gameOver(i);
            if(flag){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    private boolean gameOver(int steps){
        if(winner != null){
            return true;
        }else {
            if(steps >= 100){
                winner = Thread.currentThread().getName();
                System.out.println("winner is "+winner);
                return true;
            }
        }
        return false;
    }

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

并发问题(资源)

// 多个线程操作同一个对象
// 多个线程操作同一个资源,线程不安全,数据不一致
public class TestThead2 implements Runnable{

    // 票数
    private int ticket = 10;

    public void run() {
        while (true) {
            if(ticket < 1)
                break;
            // 延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了"+ticket--);

        }
    }

    public static void main(String[] args) {
        TestThead2 testThead2 = new TestThead2();

        new Thread(testThead2,"S").start();
        new Thread(testThead2,"A").start();
        new Thread(testThead2,"H").start();
    }
}

静态代理模式

真实对象和代理对象都要实现同一个接口,代理对象代理真实对象

package com.henry;


public class StaticProxy {
    public static void main(String[] args) {
        
       new Thread(()-> System.out.println("来了")).start();
       new Company(new Peo()).HappyMarry();
    }
}

interface Marry{
    void HappyMarry();
}

// 真实角色
class Peo implements Marry {

    public void HappyMarry() {
        System.out.println("peo要结婚了");
    }
}

// 代理角色
class Company implements Marry{
    // 真实代理角色
    private Peo target;

    public Company(Peo target) {
        this.target = target;
    }

    public void HappyMarry() {
        before();
        target.HappyMarry();
        after();
    }

    private void before() {
        System.out.println("结婚前准备");
    }

    private void after() {
        System.out.println("结账");
    }
}

lamda表达式

函数式接口:接口只包含唯一一个抽象方法

package com.henry;

public class lamdaTest {
    public static void main(String[] args) {
        Peo p = new like();
        p.lamda();

        // 匿名内部类
        p = new Peo() {
            @Override
            public void lamda() {
                System.out.println("aa");
            }
        };
        p.lamda();
        // lamda
        p = ()-> System.out.println("bb");
        p.lamda();
    }
}


interface Peo{
    void lamda();
}

class like implements Peo {

    @Override
    public void lamda() {
        System.out.println("henry");
    }
}

带参数的

public class LamdaTest2 {
    public static void main(String[] args) {
        Ha h = new Hen();
        h.ha("aa");

        h = new Ha() {
            @Override
            public void ha(String s) {
                System.out.println(s);
            }
        };
        h.ha("nn");

        h = (String s)-> {
            System.out.println(s);
        };
        h.ha("kk");
        // 简化去掉参数类型
        h = (s)->  {
            System.out.println(s);
        };
        // 去掉花括号,仅限于一行代码
        h = (s)-> System.out.println(s);

    }
}

interface Ha{

    void ha(String s);
}

class Hen implements Ha{

    @Override
    public void ha(String s) {
        System.out.println(s);
    }
}

线程状态

image

线程停止

// 建议线程正常停止
// 不要使用stop或者destroy
public class TestStop implements Runnable{

    // 设置一个标志
    private boolean flag = true;
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("进行==="+i++);
        }

    }
	// 修改标志位
    public void stop() {
        flag = false;
    }


    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i < 300; i++) {
            System.out.println("main"+i);
            if(i == 200){
                testStop.stop();
                System.out.println("停止");
            }
        }
    }
}

线程休眠

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

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

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

// 多个线程操作同一个对象
// 多个线程操作同一个资源,线程不安全,数据不一致
public class TestThead2 implements Runnable{

    // 票数
    private int ticket = 10;

    public void run() {
        while (true) {
            if(ticket < 1)
                break;
            // 延时
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了"+ticket--);

        }
    }

    public static void main(String[] args) {
        
    }
}

倒计时功能

public class TestSleep2 {

    public static void main(String[] args) throws InterruptedException {
        //tenDown();
        Date date = new Date(System.currentTimeMillis());
        while (true) {
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
            Thread.sleep(1000);
            date =  new Date(System.currentTimeMillis());
        }
    }

    // 倒计时
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while(true) {
            System.out.println(num--);
            Thread.sleep(1000);
            if (num <= 0) {
                break;
            }
        }
    }
}

线程礼让

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

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

然后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 {

    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"停止执行");
    }
}

线程强制执行join(插队)

守护线程

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

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

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

  • 可以用来后台记录日志、监控内存、垃圾回收

thread.setDaemon(true)

线程同步机制

处理多线程问题时,多个线程访问同一个对象,有的线程还想修改这个对象,需要线程同步,线程同步是一种等待机制,多个需要同时访问此对象的线程进入这个对象的等待池形成队列

为了保证数据被访问时候的正确性,在访问时加入锁机制synchronized,当一个对象获得对象的排它锁,独占资源其他线程必须等待

问题:

image

image

image

死锁

产生死锁的条件:互斥、请求保持、不可剥夺、循环等待

public class Lock {
    public static void main(String[] args) {
        getSource g1 = new getSource(1,"aa");
        getSource g2 = new getSource(2,"bb");
        // 会锁住
        g1.start();
        g2.start();
    }
}

// 资源1
class S1{

}

// 资源2
class S2{

}

class getSource extends Thread{

    // 用static保证每个资源只有一份
    static S1 s1 = new S1();
    static S2 s2 = new S2();
    private int choice;
    private String name;

    getSource(int choice, String name) {
        this.choice = choice;
        this.name = name;
    }

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

    private void getS() throws InterruptedException {
        if(choice == 1) {
            synchronized (s1) {
                System.out.println(this.name+"获得s1");
                Thread.sleep(1000);
                synchronized (s2) {
                    System.out.println(this.name+"获得s2");
                }
            }
        } else {
            synchronized (s2) {
                System.out.println(this.name+"获得s2");
                Thread.sleep(2000);
                synchronized (s1) {
                    System.out.println(this.name+"获得s1");
                }
            }
        }
    }
}

修改同步代码,不会锁住

private void getS() throws InterruptedException {
    if(choice == 1) {
        synchronized (s1) {
            System.out.println(this.name+"获得s1");
            Thread.sleep(1000);

        }
        synchronized (s2) {
            System.out.println(this.name+"获得s2");
        }
    } else {
        synchronized (s2) {
            System.out.println(this.name+"获得s2");
            Thread.sleep(2000);

        }
        synchronized (s1) {
            System.out.println(this.name+"获得s1");
        }
    }
}

Lock锁

public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
    }
}


class TestLock2 implements Runnable {
    private int number = 10;

    // 定义lock锁
    private final ReentrantLock lock = new ReentrantLock();

    public void run() {
        while (true) {
            try {
                // 加锁
                lock.lock();
                if(number > 0) {

                    Thread.sleep(1000);
                    System.out.println(number--);
                } else {
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                 // 解锁
                lock.unlock();
            }
        }

    }
}

用synchronized

public void run() {
    while (true) {
        synchronized ("") {
            if(number > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(number--);
            } else {
                break;
            }
        }

    }
}

生产者和消费者

缓冲区(管程法)

public class TestPC {
    public static void main(String[] args) {
        Container container = new Container();
        new Producer(container).start();
        new Consumer(container).start();
    }
}

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

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("生产了"+i);
            try {
                container.push(new Product(i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

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

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("消费了"+i);
            try {
                container.pop();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

// 产品
class Product {
    private int id;

    public Product(int id) {
        this.id = id;
    }
}

// 缓冲区
class Container {
    // 容器
    Product[] products = new Product[10];

    // 计数器
    int count = 0;

    // 生产者放入产品
    public synchronized void push(Product product) throws InterruptedException {
        if (count == products.length) {
            // 通知消费者消费,生产等待
            this.wait();
        }
        products[count++] = product;
        // 通知消费者消费
        this.notifyAll();
    }

    // 消费者消费产品
    public synchronized Product pop() throws InterruptedException {
        // 判断是否可以消费
        if (count == 0) {
            // 等待生产者生产,消费者等待
            this.wait();
        }

        count--;
        this.notifyAll();
        return products[count];
    }
}

信号灯法

标志位

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

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

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2 == 0) {
                this.tv.play("开始节目"+i);
            } else {
                this.tv.play("快乐");
            }
        }
    }
}

// 消费者--观众
class Watcher extends Thread {
    TV tv;
    public Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.tv.watch();
        }
    }
}

// 产品--节目
class TV {
    String film;
    boolean flag = true;

    // 表演
    public synchronized void play(String film) {
        if(!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("表演了"+film);
        // 通知观众观看
        this.notifyAll();

        this.film = film;
        this.flag = !this.flag;
    }

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

线程池

public class TestPool {
    public static void main(String[] args) {
        // 创建线程池,参数为线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);

        service.execute(new myThread());
        service.execute(new myThread());
        service.execute(new myThread());
        // 关闭连接
        service.shutdown();
    }
}

class myThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
posted @ 2021-03-24 17:47  Henry829  阅读(43)  评论(0编辑  收藏  举报