多线程的相关概念

多线程的相关概念

1.线程的两种实现方式

继承Thread类,实现Runnable接口

package com.lili.thread;

import sun.awt.windows.ThemeReader;

/**
 * 线程的休眠
 * 在当前线程的执行中,暂停指定的毫秒数 释放cpu的时间片
 *
 * @author: QiJingJing
 * @create: 2021/7/14
 */
public class Test1 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        // 推荐
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        // 启动线程
        myThread.start();
        thread.start();

    }
}

/**
 * 实现线程的第一种方式:继承Thread类
 */
class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "-" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 实现线程的第二种方式:实现Runnable接口
 */
class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "-" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.Join与中断线程

加入线程,让调用线程先执行完毕,

package com.lili.thread;

/**
 * join方法
 * 加入线程,让调用线程先执行完毕
 *
 * @author: QiJingJing
 * @create: 2021/7/14
 */
public class Test2 {
    public static void main(String[] args) {
        MyRunnable2 myRunnable2 = new MyRunnable2();
        Thread thread2 = new Thread(myRunnable2);
        thread2.start();
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 20) {
                try {
                    // 让thread2线程执行完毕
                    thread2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                thread2.interrupt();
            }
        }
    }
}

class MyRunnable2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

中断线程适合自定义标记中断线程:

package com.lili.thread;

/**
 * @author: QiJingJing
 * @create: 2021/7/14
 */
public class Test2 {
    public static void main(String[] args) {
        MyRunnable2 myRunnable2 = new MyRunnable2();
        Thread thread2 = new Thread(myRunnable2);
        thread2.start();
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "--" + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 20) {
                myRunnable2.flag = false;
            }
        }
    }
}

class MyRunnable2 implements Runnable {
    public boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println(Thread.currentThread().getName() + "--" + i++);
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3.守护线程与yield

public final void setDaemon(boolean on):将此线程标记为daemon线程或用户线程,当运行的唯一线程是守护线程时,java虚拟机将退出

yield():让出本次cpu执行权,但不一定礼让成功

package com.lili.thread;

/**
 * 守护线程和yield
 *
 * @author: QiJingJing
 * @create: 2021/7/14
 */
public class Test3 {
    public static void main(String[] args) {
        Runnable3 runnable3 = new Runnable3();
        Thread thread = new Thread(runnable3);
        // 线程可以分为守护线程和用户线程,当进程中没有用户线程时,JVM会退出
        // 设置为守护线程
        thread.setDaemon(true);
        //设置优先级可以提高该线程抢得cpu的概率
        thread.setPriority(Thread.MAX_PRIORITY);
        thread.start();
        for (int i = 0; i < 50; i++) {
            System.out.println("main--" + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 5) {
                Thread.yield();//让出本次cpu的执行权
            }
        }
    }
}

class Runnable3 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println("--" + i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

4.线程同步

(1)同步代码块 (2)使用同步方法 (3)使用Lock锁(更灵活的代码控制)

package com.lili.thread;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 1.多线程共享数据时,会发生线程不安全的情况
 * 2、多线程共享数据必须实现同步,
 * 3.实现同步的三种方法:
 * (1 同步代码块
 * (2 使用同步方法
 * (3 使用lock(更灵活的代码控制)
 * 多线程共享数据,会有安全问题,使用同步可以解决安全问题,但同时会牺牲性能,所以同步的代码块尽量保持简短,把不随线程变化的代码移除同步,不要阻塞
 *
 * @author: QiJingJing
 * @create: 2021/7/15
 */
public class Test4 {
    public static void main(String[] args) {
        MyRunnable5 myRunnable5 = new MyRunnable5();
        Thread t1 = new Thread(myRunnable5);
        Thread t2 = new Thread(myRunnable5);
        t1.start();
        t2.start();
    }
}

class MyRunnable5 implements Runnable {
    private int ticket = 10;// 售票
    //    @Override
//    // 可以写方法中,表示为同步方法
//    public /*synchronized*/ void run() {
//        for (int i = 0; i < 300; i++) {
//                synchronized (this) {
//                    if(ticket>0){
//                    ticket--;
//                    try {
//                        Thread.sleep(1000);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    System.out.println("你购买的票剩余"+ticket+"张");
//                }
//            }
//        }
//    }
    ReentrantLock lock = new ReentrantLock();

    //lock实现同步
    @Override
    // 可以写方法中,表示为同步方法
    public void run() {
        for (int i = 0; i < 300; i++) {
            lock.lock();//上锁
            try {
                if (ticket > 0) {
                    ticket--;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("你购买的票剩余" + ticket + "张");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();//解锁
            }
        }
    }
}

5.死锁

过多的同步有可能出现死锁,死锁的操作一般是在程序运行的时候才可能出现,多线程中要进行资源的共享,就需要同步,但同步过多,就可能造成死锁:

package com.lili.thread;

/**
 * 死锁例子
 *
 * @author: QiJingJing
 * @create: 2021/7/15
 */
public class Test5 {
    private static Object obj1 = new Object();
    private static Object obj2 = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (obj1) {
                System.out.println("obj1");
                synchronized (obj2) {
                    System.out.println("obj2");
                }
            }
        }).start();
        new Thread(() -> {
            synchronized (obj2) {
                System.out.println("obj2");
                synchronized (obj1) {
                    System.out.println("obj1");
                }
            }
        }).start();
    }
}

6,生产者与消费者

(1)管程法

package com.lili.thread;

/**
 * 测试生产者消费者模型(管程法)
 *
 * @author: QiJingJing
 * @create: 2021/7/15
 */
public class Test6 {
    public static void main(String[] args) {
        Buffer buf = new Buffer();
        new Thread(new Productor(buf)).start();
        new Thread(new Consumer(buf)).start();
    }
}

// 生产者
class Productor implements Runnable {
    private Buffer buffer;

    public Productor(Buffer buffer) {
        this.buffer = buffer;
    }

    // 生产
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            buffer.push(new Chicken(i));
            System.out.println("成产了" + i + "只鸡");
        }
    }
}

// 消费者
class Consumer implements Runnable {
    private Buffer buffer;

    public Consumer(Buffer buffer) {
        this.buffer = buffer;
    }

    // 生产
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("消费了第" + buffer.pop().getId() + "只鸡");
        }
    }
}

// 产品
class Chicken {
    private int id;

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

// 缓冲区
class Buffer {
    // 需要一个容器大小
    private Chicken[] chickens = new Chicken[10];
    // 容器计数器
    private 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;
    }
}

(2)信号灯法

package com.lili.thread;

/**
 * 生产者与消费者(信号灯法)
 *
 * @author: QiJingJing
 * @create: 2021/7/15
 */
public class Test7 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Thread(new Player(tv)).start();
        new Thread(new Watcher(tv)).start();
    }
}

// 生产者->演员
class Player implements Runnable {
    private TV tv;

    public Player(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0) {
                this.tv.play("快乐大本营播放中");
            } else {
                this.tv.play("抖音:记录美好生活");
            }
        }
    }
}

// 消费者->观众
class Watcher implements Runnable {
    private 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 {
    private String voice;// 表演的节目
    private boolean flag = true;

    // 表演
    public synchronized void play(String voice) {
        if (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        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;
    }
}

7.线程池

背景:经常创建和销毁,使用量特别大的资源,比如并发下的线程,对性能影响很大

思路:提前创建好多个线程,放入线程池,使用时直接获取,使用完放回池中,可以避免频繁创建销毁,实现重复利用,类似生活中的交通工具

package com.lili.thread;

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

/**
 * @author: QiJingJing
 * @create: 2021/7/15
 */
public class Test8 {
    public static void main(String[] args) {
        // 1.创建服务,创建线程池
        // 参数为线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new MyRunnable7());
        service.execute(new MyRunnable7());
        service.execute(new MyRunnable7());
        service.execute(new MyRunnable7());
        //2. 关闭链接
        service.shutdown();
    }
}

class MyRunnable7 implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
posted @   JamieChyi  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示