多线程详解

 线程创建

三种创建方式:

1.继承Thread类

>自定义线程类继承Thread类

>重写run()方法,编写执行体

>创建线程对象,调用start()方法启动线程

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

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

//总结:注意,线程开启不一定立即执行,有cpu调度执行
public class TestThread1 extends Thread{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 200; i++) {
            System.out.println("thread" + i);
        }
    }

    public static void main(String[] args) {
        //main线程,主线程

        //创建一个线程对象
        TestThread1 testThread1 = new TestThread1();
        //调用start()方法开启线程
        testThread1.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main" + i);
        }
    }
}

2.实现Runnable接口

>定义MyRunnable类实现Runnable接口

>实现run()方法,编写线程执行体

>创建线程对象,调用start()方法启动线程

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

public class TestThread3 implements Runnable {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 200; i++) {
            System.out.println("thread" + i);
        }
    }

    public static void main(String[] args) {
        //main线程,主线程

     //创建Runnable接口的实现类对象
        TestThread3 testThread3 = new TestThread3();
        //创建线程对象,通过线程对象来开启我们的线程,代理
//        Thread thread = new Thread(testThread3);
//        thread.start();
        new Thread(testThread3).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main" + i);
        }
    }
}

3.实现Callable接口

>实现Callable接口,需要返回值类型

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

>创建目标对象

>创建线程池:ExecutorService executorService = Executors.newFixedThreadPool(1);

>提交执行:Future<Boolean> submit = executorService.submit(testCallable);

>获取结果(会阻塞主线程):Boolean aBoolean = submit.get();

>关闭线程池:executorService.shutdown();

public class TestCallable implements Callable<Boolean> {
    @Override
    public Boolean call() {
        //call方法线程体
        for (int i = 0; i < 200; i++) {

            System.out.println("thread" + i);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //main线程,主线程

        //创建接口的实现类对象
        TestCallable testCallable = new TestCallable();
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        //提交执行线程
        Future<Boolean> submit = executorService.submit(testCallable);
        //获取结果--get()方法会阻塞主线程
        Boolean aBoolean = submit.get();

        //关闭线程池
        executorService.shutdown();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main" + i);
        }
    }
}

线程状态

 线程停止

>推荐线程自己停止,自定义中断标识符

//测试停止线程
//1.建议线程正常停止--》利用次数,不建议死循环
//2.建议使用标志位-->设置一个标志位
//3.不要使用stop或者destroy等过时的方法
public class TestStop implements Runnable{

    //1.设置一个标识位
    private boolean flag =true;
    @Override
    public void run() {
        int i =0;
        while (flag){
            System.out.println("run...Thread"+i++);
        }
    }
    //2.设置一个公开的方法停止线程,转换标志位
    public  void myStop(){
        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.myStop();
                System.out.println("线程停止了");
            }
        }
    }
}

线程休眠

>Thread.sleep();

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

>sleep存在异常InterruptedException

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

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

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

   public static void main(String[] args) {
        Date startTime = new Date(System.currentTimeMillis());
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime=new Date(System.currentTimeMillis());//更新当前时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

线程礼让

>Thread.yield();

>礼让线程,将线程从运行状态转为就绪状态

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

线程强制执行

>thread.join();

>用于在当前线程A中添加别的线程B,这时线程A被阻塞,处于Blocked状态,线程B开始执行,当线程B执行完以后,线程A才能进行执行

    public static void main(String[] args) throws InterruptedException {
        Thread threadJoin = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int i = 0; i < 1000; i++) {
                    System.out.println("线程插入进来了" + i);
                }
            }
        });
        threadJoin.start();

        for (int i = 0; i < 1000; i++) {
            if(i==200){
                threadJoin.join();
            }
            System.out.println("main" + i);
        }
    }

线程优先级

>thread.setPriority(int);    设置线程优先级方法

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

>默认优先级都是5

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

>优先级设置在start()之前

守护(daemon)线程

>thread.setDaemon(boolean);      true表示设置为守护线程

>线程分为用户线程和守护线程,正常的线程都是用户线程

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

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

>如后台记录操作日志、监控内存、垃圾回收

线程同步

 >线程同步是指多线程通过特定的设置(如互斥量,事件对象,临界区)来控制线程之间的执行顺序(即所谓的同步)也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步,那线程之间是各自运行各自的!

synchronized

>普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁

静态同步方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁

同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁

//obj 锁定的对象
   synchronized(obj)
   {
      // todo
   }

死锁

>所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。 因此我们举个例子来描述,如果此时有一个线程A,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,按照先锁b再锁a的顺序获得锁。

Lock(锁)

>java.util.concurrent.locks.Lock 是一个类似于synchronized 块的线程同步机制。但是 Lock比 synchronized 块更加灵活。Lock是个接口,有个实现类是ReentrantLock

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

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

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

class A{
    //定义lock锁
    private final ReentrantLock lock=new ReentrantLock();
    public void m(){
        lock.lock();//加锁
        try {

        }finally {
            lock.unlock();//解锁
            //如果代码有异常,要将unlock()写入final语句块
        }
    }
}

wait()和notify(),notifyAll( )

>如果一个线程调用了 object.wait() 方法,那么它就会进入 object 对象的等待队列(wait set)。

这个等待队列中,可能会有多个线程,因为系统运行多个线程同时等待某一个对象。

当 object.notify() 方法被调用时,它就会从这个等待队列中随机选择一个线程,并将其唤醒。

这里希望大家注意的是,这个选择是不公平的,并不是先等待的线程就会优先被选择,这个选择完全是随机的。

 

 线程池

>ExecutorService:线程池接口

>void execute(Runnale):执行任务命令,没有返回值,一般用来执行Runnale

>Future<T> submit(Callable<T>):执行任务,有返回值,一般用来执行Callable

>void shutdown():关闭线程池

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

>提前创建好多个线程,放入线程池,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值