多线程

1.创建线程方式

创建线程方式一:继承Thread类,重写run()方法,调用start开启线程

总结:线程开启不一定立即执行,有cpu调度执行

package com.zhang.linePro;
public class TestThread1 extends Thread {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i <200 ; i++) {
            System.out.println("我在看代码");
        }
    }
    public static void main(String[] args) {//main()线程 ,主线程
        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();
        //调用start方法开启线程
        testThread1.start();//方法二:new Thread(testThread1).start();
        for (int i = 0; i <1000 ; i++) {
            System.out.println("我在学习多线程");  //我在学习和我在看代码交替执行
        }
    }
}

创建线程方法二: 实现runnable接口,重写run()方法,执行线程需要丢入Runnable接口实现类,调用start方法

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

创建线程方法三:实现callable接口 callable好处:可以定义返回值,可以抛出异常。

2.Lamda表达式

package com.zhang.linePro;
public class Demo02 {
    public static void main(String[] args) {
        Ilova ilova = ()->{
            System.out.println("aini");
        };
        ilova.love();
    }
    interface Ilova{
        void love();
    }
}

3.线程停止

推荐线程自己停下来,建议使用一个标志位进行终止变量,当flag=false,终止线程运行

package com.zhang.linePro;
public class TestStop implements Runnable {
    private boolean flag=true;
    @Override
    public void run() {
        for (int i = 0; i <1000 ; i++) {
            while (flag){
                System.out.println("xiancheng"+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 <1000 ; i++) {
            System.out.println("main"+i);
            if (i==900) {testStop.Stop();//当主线程中的i到900的时候,次线程就停止,后面不在输出xianchengi了
            System.out.println("线程该停止了");}
        }
    }
}

4.线程礼让(yield)

将线程从运行状态转为阻塞状态。让cpu重新调度,礼让不一定成功

package com.zhang.linePro;
public class TestYield {
    public static void main(String[] args) {
        MyYield myYield = new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
    static class MyYield implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"线程开始");
            Thread.yield();//线程礼让
            System.out.println(Thread.currentThread().getName()+"线程开始");
        }
    }
}

5.线程强制执行(join)

package com.zhang.linePro;
public class TestYield {
    public static void main(String[] args) throws InterruptedException {
        MyYield myYield = new MyYield();
        Thread thread = new Thread(myYield);
        thread.start();
        for (int i = 0; i < 500; i++) {
            if (i==200) thread.join(); //线程执行到1000,主线程才能执行剩下的
            System.out.println("zhuxian"+i);
        }
    }
    static class MyYield implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                System.out.println("vip"+i);
            }
        }
    }
}

线程五大状态

  1. new 尚未启动
  2. RUNNABLE 运行
  3. BLOCK 阻塞
  4. TIMED_WAITTING timed_waitting 等待
  5. TERMINATED terminated 终止

线程优先级

先设置优先级,再启动。

Thread thread = new Thread(myYield);
thread.setPriority(2)//线程优先级1-10
thread.start();

守护线程

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

虚拟机不用等待守护线程执行完毕,但是必须确保用户线程执行完毕

守护线程:后台记录操作日志,监控内存,垃圾回收等。

Thread thread = new Thread(myYield);
thread.setDaemon(true)//默认是false表示用户线程
thread.start();

6.线程同步机制

7.死锁

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
package com.zhang.linePro;
//死锁:多个线程互相拿着对方所需的资源,形成死锁
public class DeadBlock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0,"灰姑娘");
        Makeup g2 = new Makeup(1,"小公猫");
        new Thread(g1).start();
        new Thread(g2).start();
    }
}
//资源
class Lipstick{
 //口红
}
class Mirror{
//镜子
}
class Makeup implements Runnable{  //化妆
    //需要的资源只有一份,用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;
    }
    //化妆,互相持有对方的锁,持有对方所需的资源
    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 + "获得口红");
                }
            }

        }
    }
    @Override
    public void run() {
        try {   //化妆
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

想破开这个死锁:把资源变成多份或者是把使用时间调成一致,再或者是把下面的死锁从上个死锁里拿出来(口红用完了再等一秒,等别人把镜子用完了,你再用)

Lock锁

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

Lock锁和synchronized的对比

  1. Lock锁是显式锁(手动开启锁,别忘记手动关闭锁)。synchronized是隐式锁,出了作用域自动释放。

  2. Lock只有代码块锁,synchronized有代码块锁和方法锁

  3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

  4. 优先使用顺序:Lock>同步代码块(已经进了方法体,分配了相应资源)>同步方法

package com.zhang.linePro;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock1 testLock = new TestLock1();
        new Thread(testLock).start();
        new Thread(testLock).start();
        new Thread(testLock).start();
    }
}
class TestLock1 implements Runnable{
    int ticketnums=10;
    //定义lock锁
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while(true) {
            try{lock.lock();  //加锁
                if (ticketnums > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticketnums--);
                }else break;
            }finally {
                lock.lock();  // 解锁
            }
        }
    }
}
posted on 2023-03-15 10:13  似初吖  阅读(12)  评论(0编辑  收藏  举报