多线程笔记

多线程

普通方法

只有主线程一条执行路径

多线程

多条执行路径,主程序和子程序并行交替执行

Process(进程)与Thread(线程)

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

进程 里面可以有若干个线程但至少会有一个线程

线程不一定执行看cpu调度

线程三种方式Thread类 Runnable接口 collection接口

Thread

//总结:线程开启不一定立即执行,由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);
        }
    }
}

文件的下载多线程

文件的下载顺序会不一样看方法的调度

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();
        try {
            webDownloader.downloader(url, name);
            System.out.println("下载了文件为"+name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img-home.csdnimg.cn/images/20210924092214.jpg","1.jpg");
        TestThread2 t2 = new TestThread2("https://i0.hdslb.com/bfs/feed-admin/d7c2a5fd2d583f246b3ed95c9ea49d9ec60c5371.jpg@880w_388h_1c_95q","2.jpg");
        t1.start();
        t2.start();
    }
}
    //下载器
    class WebDownloader{
        //下载方法
        public void downloader(String url,String name) throws IOException {
            FileUtils.copyURLToFile(new URL(url),new File(name));
            System.out.println("IO异常,downloader方法出现问题");
        }
    }

Runable接口

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() {
        WebDownloader webDownloader = new WebDownloader();
        try {
            webDownloader.downloader(url, name);
            System.out.println("下载了文件为"+name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        TestThread2 t1 = new TestThread2("https://img-home.csdnimg.cn/images/20210924092214.jpg","1.jpg");
        TestThread2 t2 = new TestThread2("https://i0.hdslb.com/bfs/feed-admin/d7c2a5fd2d583f246b3ed95c9ea49d9ec60c5371.jpg@880w_388h_1c_95q","2.jpg");
        new Thread(t1).start();
        new Thread(t2).start();
    }
}
    //下载器
    class WebDownloader{
        //下载方法
        public void downloader(String url,String name) throws IOException {
            FileUtils.copyURLToFile(new URL(url),new File(name));
            System.out.println("IO异常,downloader方法出现问题");
        }
    }
继承Thread

子类继承Thread类具备多线程能力

启动线程 子类对象.start()

不建议使用避免oop单继承局限

实现Runable

实现接口Runable具备多线程能力

启动程序传入目标对象+Thread对象.start()

推荐使用避免了单继承局限,灵活方便,方便同一个对象被多个线程使用

初始并发
public class Thread4  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) {
        Thread4 thread4 = new Thread4();
        new Thread(thread4,"小明").start();
        new Thread(thread4,"老师").start();
        new Thread(thread4,"黄牛").start();

    }
}
//模拟龟兔
public class Race implements Runnable{
    private static String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if (Thread.currentThread().getName().equals("兔子")){
                try {
                    Thread.sleep(5);
                } 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;
        }{
            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();
    }
}

实现Callable接口

实现Callable接口,需要返回值

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

创建执行服务

提交执行

获取结果

关闭服务

        TestCallable t1 = new TestCallable();
        
        TestCallable t2 = new TestCallable();
        
        ExecutorService ser = Executors.newFixedThreadPool(2);
        
        Future<String> r1  = ser.submit(t1);
        
        Future<String> r2  = ser.submit(t2);
        
        String re1 = r1.get();
        
        String re2 = r2.get();
        
        System.out.println(re1);
        
        System.out.println(re2);
        
        ser.shutdown();

静态代理

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

代理对象要代理真实对象

好处:

代理对象可以做很多真实对象做不了的事情

真实对象专注做自己的事情

public class StaticProxy {
    public static void main(String[] args) {
        You you = new You();
        // Lambda表达式
         new Thread(()-> System.out.println("111")).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("结婚前,布置现场");
    }
}
public class TestLambda {
    //3.静态内部类
    static class Like2 implements Ilike{

        @Override
        public void lambda() {

        }
    }
    public static void main(String[] args) {
        Ilike like = new Like();
        like.lambda();
        like = new Like2();
        //局部
        class Like3 implements Ilike{

            @Override
            public void lambda() {

            }
        }
        like = new Like3();
        like.lambda();
        //5.匿名 没有类的名称,必须借助接口或者类的名称
        like = new Ilike() {
            @Override
            public void lambda() {
                System.out.println("4");
            }
        };
        like.lambda();
        //6.用lambda
        like = ()->{
            System.out.println("5");
        };
        //7.简化
        like = ()-> System.out.println("6");
        like.lambda();
    }
}
    interface Ilike{
        void lambda();
    }
    class Like implements Ilike{

        @Override
        public void lambda() {
            System.out.println("I Like");
        }
    }
总结:

lambda表达式只能有一行代码的情况下才能简化代码,如果有多行,那么就用代码块包裹

前提是接口为函数式接口

多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号

线程五大状态

创建newThread

就绪start

阻塞 sleep wait

运行

dead(中断或结束)

setPriority(int new Priority) 更改优先级
sleep 睡眠
join 等待该线程终止
yield 暂停
interrupt 中断
isAlive 测试
测试stop

1.建议正常停止 —> 利用次数,不建议死循环
2.不建议使用标准位 -->设置一个标致位
3.不要使用stop或者destory等过时或者jdk不建议

public class TestStop implements Runnable {
//设置一个标致位
    boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag){
            System.out.println("run ... Thread"+i++);
        }
    }
    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){
                testStop.stop();
                System.out.println("线程停止了");
            }
        }
    }
}
sleep线程睡眠

模拟倒计时

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

模拟获取当前时间

public class TestSleep3 {
    public static void main(String[] args) {
        Date time = new Date(System.currentTimeMillis());
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(time));
             time = new Date(System.currentTimeMillis());
        }
    }
    public static void tenDown() throws InterruptedException {
        int num  = 10;
        while (true){
            Thread.sleep(1000);
            System.out.println(num--);
            if (num<=0){
                break;
            }
        }
    }

}
线程礼让

让当前的线程暂停,但不阻塞

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

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

package com.project.thread;
//礼让不一定成功看心情
public class TestYied {
    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.project.thread;
//测试join
public class TestJoin implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 500; 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 < 1000; i++) {
            if (i==200){
                thread.join();//插队
            }
            System.out.println("main"+i);
        }
    }
}
线程状态
package com.project.thread;
//观察线程状态
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(i);
            }
            System.out.println("/");
        });
        Thread.State state = thread.getState();
        System.out.println(state);
        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);
        }
    }
}

线程优先级

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

getPriority()

setPriority(int xxx)

package com.project.thread;

public class TestPriority  extends Thread{
    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);
        t4.start();
        t5.setPriority(8);
        t5.start();
        t6.setPriority(7);
        t6.start();
    }
    static class MyPriority implements  Runnable{

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
        }
    }
}

守护线程

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

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

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

package com.project.thread;

public class TestDaemom {
    public static void main(String[] args) {
        God god = new God();
        you you1 = new you();
        Thread thread = new Thread(god);
        thread.setDaemon(true); //默认是false表示用户线程,正常的线程都是用户线程
        thread.start();//上帝守护线程启动
        new Thread(you1).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 < 36500; i++) {
            System.out.println("你一生开心活着");
        }
        System.out.println("====goodbye you");
    }
}

线程同步

多个线程操作同一个资源

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

多线程访问同一个对象叫并发

形成条件:队列+锁

问题解决队列加锁

不安全线程

arraylist

同步方法

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

pubic synchronize void method(int arges){}

缺陷:加上synchronize会大大影响效率

锁太多就浪费资源所以就有锁块

原理:每个人都要排队,当第一个人拿完了下一个人才可以拿

锁默认锁的是this就是本身

所以就需要同步块

synchronized(Obj){}

Obj称之为同步监视器

JUC并发测试
//测试
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                copyOnWriteArrayList.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(copyOnWriteArrayList.size());
    }
}

死锁

多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对象释放资源,都停止执行的情形某一个同步块同时拥有“两个以上对象的锁”时,就有肯发生死锁问题

产生死锁条件

互斥条件:一个资源只能被一个进程使用

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

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

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

package com.project.thread;
//死锁
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 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 {
            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(2000);
            }
            synchronized (lipstick){
                System.out.println(this.girlName+"获得口红的锁");
            }
        }
    }
}
Lock(锁)

显示定义的锁

synchronize和Lock的对比

Lock是显示锁(手动开启和关闭,别忘记关闭锁)synchronize是隐式锁,出了作用域自动释放

Lock只有代码块锁,synchronize有代码锁和方法锁

使用Lock jvm将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性

使用顺序

Lock 同步代码块 同步方法

package com.project.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock2 lock2 = new TestLock2();
        new Thread(lock2).start();
        new Thread(lock2).start();
        new Thread(lock2).start();
    }
}
class TestLock2 implements Runnable{
    int tick = 10;

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

生产者和消费者(线程通信)

java提供了几个方法解决线程之间的通信问题

方法名作用
wait()表示线程会一直等待,直到其它线程通知,与sleep不同,会释放锁
wait(long timeout)指定等待的毫秒数
nofity()唤醒一个处于等待状态的线程
nofityAll()唤醒同一个方法上所有调用wait()方法的线程,优先级别高的线程优先度

解决方式:

生产者/消费者模式

管程法
package com.project.gaoji;

import javax.swing.plaf.synth.SynthConstants;

//测试:生产者和消费者 -》利用缓冲区解决:管程法
//生产者
public class TestPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Consumer(container).start();
    }
}
//生产者
class Productor extends Thread{
    SynContainer container;
    public Productor(SynContainer container){
        this.container = container;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            container.push(new Chicken(i));
            System.out.println("生产了"+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{
    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;
    }

}

信号灯法
package com.project.gaoji;

public class Test2 {
    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){
                this.tv.plays("快乐在播放");
            }else {
                this.tv.plays("抖音:记录美好生活");
            }
        }
    }
}
//消费者 观众
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 plays(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;

    }
}

线程池

提高响应速度

降低资源消耗

便于线程管理

ExecutorService和Executors

package com.project.Poll;

import org.apache.ibatis.executor.Executor;

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

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.execute(new MyThread());
        service.execute(new MyThread());
        //关闭
        service.shutdown();
    }
}
class MyThread implements Runnable{

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

  this.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    System.out.println("观众观看"+voice);
    this.notifyAll();
    this.flag = !this.flag;

}

}


### 线程池

提高响应速度

降低资源消耗

便于线程管理

ExecutorService和Executors

package com.project.Poll;

import org.apache.ibatis.executor.Executor;

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

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.execute(new MyThread());
service.execute(new MyThread());
//关闭
service.shutdown();
}
}
class MyThread implements Runnable{

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

}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏来梦栀子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值