Java多线程完结!!!

线程状态(20-12-09)

new -->就绪状态 <-->运行状态-->dead

阻塞状态-->就绪状态<-->运行状态-->阻塞状态

停止线程:

不推荐使用JDK提供的stop()、destroy()方法

推荐线程自己停止下来

建议使用一个标志位进行终止变量,当flag=false,则终止线程运行

线程休眠

sleep(时间)指定当前线程阻塞的毫秒数

sleep存在异常InterruptedException

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

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

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

线程礼让 yield

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

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

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

线程强行执行 join

join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

可以想象成插队

线程状态观测 state

Thread.State;//五大状态

线程优先级 priority

优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调度了。这都是看CPU的调度

守护线程 daemon

线程分为用户和守护线程

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

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

如,后台记录操作日志,监控内存,垃圾等待回收等待

线程同步(20-12-09)

线程安全 synchronized

线程同步:多个线程操作同一个资源

例.线程不安全的集合

public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        for(int i=0 ; i<10000;i++){
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

同步方法:synchronized 方法 和 synchronized 块

前者直接在方法上加就可以;后者要把方法体包在synchronized 块中

锁的对象就是变化的量,需要增删改的对象!!!

或使用本身就是安全的类 CopyOnWriteArrayList

public static void main(String[] args) {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
        //CopyOnWriteArrayList本身就是线程安全的
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

死锁(20-12-09)

死锁:多个线程互相抱着对方需要的资源,然后形成僵持

死锁第四个必要条件:

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

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{

    int ticketNums=10;

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

    @Override
    public void run() {
        while (true){
           try {//加锁要使用try finally
            lock.lock();//加锁
            if(ticketNums>0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ticketNums--);
            }else {
                break;
            }
        }
        finally{
            lock.unlock();
           }
        }
    }
}

synchronized 与 Lock 的对比

Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁, 出了
作用域自动释放
Lock只有代码块锁,syrichronized有代码块锁和方法锁
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展
性(提供更多的子类)
优先使用顺序:
Lock >同步代码块(已经进入了方法体,分配了相应资源) >同步方法(在方法体之外)

线程通信(20-12-09)

生产者/消费者问题

管程法

生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据

...

信号灯法

设置一个标志位

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){
                this.tv.play("快乐大本营");
            }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++) {
            tv.watch();
        }
    }
}

class TV{

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

}

线程池(20-12-09)

ExecutorService:真正的线程池接口。常见子类 ThreadPoolExecutor

Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

总结

三种线程创建

//回顾线程创建
public class ThreadNew {
    public static void main(String[] args) {
        new MyThread1().start();

        new Thread(new MyThread2()).start();

        FutureTask<Integer> futureTask=new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();

        try {
            Integer integer=futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

//1.继承Thread类
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}

//2.实现Runnable接口
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}

//3.实现Callable接口
class MyThread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}
posted @ 2020-12-09 22:05  None1014  阅读(64)  评论(0编辑  收藏  举报