7 多线程基础

本文介绍了Java中的多线程基础知识,包括程序、进程和线程的概念,以及创建线程的三种方法:继承Thread类、实现Runnable接口和实现Callable接口。同时,文章讨论了线程的生命周期、线程安全问题,如同步代码块、同步方法和Lock锁的使用,以及线程同步的优缺点和死锁示例。
摘要由CSDN通过智能技术生成

7 多线程基础

7.1 程序、进程、线程

  • 程序(program):为达目的而编写的一组静态代码;
  • 进程(process):资源分配的基本单位;
  • 线程(thread):资源调度的基本单位。

7.2 创建线程的三种方法

7.2.1 继承Thread类

继承Thread类,并重写run()方法

public class test {

    public static class BuyTicketThread extends Thread {
        public BuyTicketThread(String name){
            super(name);
        }
        //一共10张票:
        static int ticketNum = 10;//多个对象共享10张票

        @Override
        public void run() {
            //每个窗口后面有100个人在抢票:
            for (int i = 1; i <= 100 ; i++) {
                if(ticketNum > 0){//对票数进行判断,票数大于零我们才抢票
                    System.out.println("我在"+this.getName()+"买到了从北京到哈尔滨的第" + ticketNum-- + "张车票");
                }
            }
        }
    }

    public static void main(String[] args) {
        //多个窗口抢票:三个窗口三个线程对象:
        BuyTicketThread t1 = new BuyTicketThread("窗口1");
        t1.start();
        BuyTicketThread t2 = new BuyTicketThread("窗口2");
        t2.start();
        BuyTicketThread t3 = new BuyTicketThread("窗口3");
        t3.start();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y1C1pGcb-1677247441577)(images/cZxFgeP-WYxZQ5DkpuwGyzuExItBmXuEczxPTeSI_XQ.png)]

7.2.2 实现Runnable接口

implements Runnable接口,并实现run()方法

package test;

public class test {

    public static class BuyTicketThread implements Runnable {
        int ticketNum = 10;
        @Override
        public void run() {
            for (int i = 1; i <= 100 ; i++) {
                if(ticketNum > 0){
                    System.out.println("我在"+Thread.currentThread().getName()+"买到了北京到哈尔滨的第" + ticketNum-- + "张车票");
                }
            }
        }
    }

    public static void main(String[] args) {
        BuyTicketThread t = new BuyTicketThread();
        Thread t1 = new Thread(t,"窗口1");
        t1.start();
        Thread t2 = new Thread(t,"窗口2");
        t2.start();
        Thread t3 = new Thread(t,"窗口3");
        t3.start();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lYrbztoL-1677247441578)(images/2WuheXY5K6o2YF6EyXdoXPQe3RLkWtHQijK-D5FKUjk.png)]

7.2.3 实现Callable接口

JDK 1.5之后提出。

它可以抛出异常,并能返回值

public class test {

    public static class TestRandomNum implements Callable<Integer> {
        /*
        1.实现Callable接口,可以不带泛型,如果不带泛型,那么call方式的返回值就是Object类型
        2.如果带泛型,那么call的返回值就是泛型对应的类型
         */
        @Override
        public Integer call() throws Exception {
            return new Random().nextInt(10);//返回10以内的随机数
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //定义一个线程对象:
        TestRandomNum trn = new TestRandomNum();
        FutureTask ft = new FutureTask(trn);
        Thread t = new Thread(ft);
        t.start();
        //获取线程得到的返回值:
        Object obj = ft.get();
        System.out.println(obj);
    }

}

7.2.4 三种方式小结

  • 实际开发中,Runnable比Thread方式用的更多,因为只能extends一个,但可以implements多个;
  • 在需要返回值时使用Callable接口;
  • 本质上只有一种方法:new Tread对象,调用run()方法。

7.3 线程的生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GolkOr9m-1677247441581)(images/obdWY4qnO2itdzGKjbVtYm15VhzbPKd1o4eHzV4-RlE.png)]

sleep和join的区别:

  • sleep期间不会释放对象锁;
  • join期间会释放对象锁。

7.4 线程安全问题

同步代码块

synchronized(object) {…}

  1. 锁住的必须是引用数据类型,不能是基本数据类型;
  2. 可以创建一个专门的同步监视器private static final Object object = new Object(),没有任何业务含义;

同步方法

  • public static synchronized void buyTicket(){…}
  • public synchronized void buyTicket(){…}

Lock锁

package test;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class test2 {
    public static class BuyTicketThread implements Runnable {
        int ticketNum = 10;
        //拿来一把锁:
        Lock lock = new ReentrantLock();//多态  接口=实现类  可以使用不同的实现类
        @Override
        public void run() {
            //此处有1000行代码
            for (int i = 1; i <= 100 ; i++) {
                //打开锁:
                lock.lock();
                try{
                    if(ticketNum > 0){
                        System.out.println("我在"+Thread.currentThread().getName()+"买到了北京到哈尔滨的第" + ticketNum-- + "张车票");
                    }
                }catch (Exception ex){
                    ex.printStackTrace();
                }finally {
                    //关闭锁:--->即使有异常,这个锁也可以得到释放
                    lock.unlock();
                }
            }
            //此处有1000行代码
        }
    }

    public static void main(String[] args) {
        BuyTicketThread t = new BuyTicketThread();
        Thread t1 = new Thread(t,"窗口1");
        t1.start();
        Thread t2 = new Thread(t,"窗口2");
        t2.start();
        Thread t3 = new Thread(t,"窗口3");
        t3.start();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XGjdw94t-1677247441582)(images/OOo2fZ-msxuuN5QMOb4Ir167dn5C3rdT5ferXPd07fI.png)]

Thread 3 在执行完第三次for循环后,关闭了锁。

此时,Thread 1 抢占了锁。

Lock和synchronized的区别

  • Lock是显式锁(手动开启和关闭锁),synchronized是隐式锁;
  • Lock只有代码块锁,synchronized有代码块锁和方法锁;
  • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。

线程同步的优缺点

  • 是否进行线程同步?
    线程安全,但效率低
    线程不安全,但效率高

  • 可能造成死锁:不同线程分别占用对方需求的资源不放弃,造成了死锁。


public static void main(String[] args) {
    Object o1 = new Object();
    Object o2 = new Object();
    Thread t1 = new Thread() {
        public void run() {
            synchronized (o1) {
                try {
                    sleep(1000);//等待t2线程上好他的o2锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o2) {
                    System.out.println(1);
                }
            }
        }
    };
    Thread t2 = new Thread() {
        public void run() {
            synchronized (o2) {
                try {
                    sleep(1000);//等待t1线程上好他的o1锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o1) {
                    System.out.println(2);
                }
            }
        }
    };
    t1.start();
    t2.start();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值