多线程(创建方式、生命周期、同步锁、死锁)

24 篇文章 1 订阅

多线程

线程创建方式一

继承Thread类。

/**
 *
 * 线程的创建方式一:
 *      A、继承了Thread类 重写run方法
 *      B、start开启线程     start()--->JVM--->run();
 *      C、线程和线程之间是竞争关系,共同争抢CPU的资源 所以每次执行结果不一定相同
 */
public class TestA {

    public static void main(String[] args) {
        DemoThread thread = new DemoThread("兔子");

        DemoThread thread2 = new DemoThread("乌龟");

        thread.setPriority(10);//设置线程的优先级 范围是【1-10】 数字越大优先级越高
        thread2.setPriority(10);

        //Thread.currentThread().setPriority(1);//设置主线程的优先级

        //System.out.println( thread.getPriority());//获得线程的优先级 默认是5
        //System.out.println( thread2.getPriority());

        thread.start();//启动兔子的线程
        thread2.start();//启动乌龟的线程

        //main主线程的代码
        System.out.println("main线程");
    }
}
class DemoThread extends Thread{

    private String name;

    public DemoThread() {
    }
    public DemoThread(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 1; i < 100; i++) {
            System.out.println(name+"跑了"+i+"米");
        }
    }
}
//run() 线程体,线程要完成的任务
//start() 启动线程,线程进入就绪队列,等待获取CPU并执行

线程的创建方式二

实现Runnable接口。

/**
 *
 * 线程的创建方式二
 *      【1】实现了Runnable接口 重写run方法
 *      【2】开始线程的时候  Thread tuzi = new Thread(demoRunnable,"兔子");
 *      tuzi.start();
 *  优点:
 *      【1】解决了java中单继承的特点
 *      【2】可以实现县城之间的数据共享
 */
public class TestB {
    public static void main(String[] args) {

        DemoRunnable demoRunnable = new DemoRunnable();
        //兔子线程
        Thread tuzi = new Thread(demoRunnable,"兔子");
        Thread wugui = new Thread(demoRunnable,"乌龟");
        
        tuzi.start();
        wugui.start();
    }
}
class DemoRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"米");
        }
    }
}
两种方式的优缺点

方式一:继承Thread类

缺点:Java单继承,无法继承其他类;优点:代码稍微简单

方式二:实现Runnable接口

优点:还可以去继承其他类,便于多个线程共享同一个资源;缺点:代码略有繁琐。实际开发中,方式二使用更多一些

Thread的属性和方法
currentThread();	//返回对当前正在执行的线程对象的引用

getName();			//返回线程的名称

getPriority();		//返回线程的优先级

run();				//如果该线程是使用独立的Runnable运行对象构造的,则调用该Runnable对象的run方法;否则,该方法不执行任何操作并返回。
setName();			//改变线程名称,使之参数name相同
setPriority();		//改变线程的优先级
start();			//使该线程开始执行;Java虚拟机调用该线程的run方法。

线程的创建方式三

JDK1.5后推出了第三种定义线程的方式,实现Callable接口。改该方式最大的变化是可以有返回值,并且可以抛出检查异常。

/**
 *
 * 线程的实现方式三:
 *      【1】implements Callable<> 重写call()
 *      【2】 DemoCallable demoCallable = new DemoCallable();
 *          FutureTask futureTask = new FutureTask(demoCallable);
 *          Thread thread1 = new Thread(futureTask);
 *          thread1.start();
 *      优点:
 *      【1】JDK1.5以后提供的,并发线程实现方式是java.util.concurrent包下的
 *      【2】call()方法可以获得返回值
 *      【3】call()方法是可以抛出异常的
 *
 */
public class TestC {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        DemoCallable demoCallable = new DemoCallable();

        FutureTask futureTask = new FutureTask(demoCallable);
        FutureTask futureTask2 = new FutureTask(demoCallable);

        Thread thread1 = new Thread(futureTask,"线程A");
        Thread thread2 = new Thread(futureTask2,"线程B");

        thread1.start();
        thread2.start();

        System.out.println("线程A是否取消"+futureTask.isCancelled());
        futureTask.cancel(true);
        System.out.println("线程A是否取消"+futureTask.isCancelled());

        //接收线程方法的返回值  等待线程运行结束才可以获得返回值
        if (!futureTask.isCancelled()&& !futureTask2.isCancelled()){

            System.out.println(futureTask.get());//获得方法的返回值
            System.out.println(futureTask2.get());
        }

    }
}

class DemoCallable implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        int i = new Random().nextInt(10);
        System.out.println(Thread.currentThread().getName()+"产生的随机数为:"+i);
        return i;
    }
}

与Runnable相比,Callable功能更强大写

  • 方法名不同
  • 可以有返回值,支持泛型的返回值
  • 可以抛出检查异常
  • 需要借助FutureTask,比如获取返回结果

线程的生命周期

线程的生命周期

  • join()

    阻塞指定线程等到另一个线程完成以后再继续执行(插队,谁调用的谁先执行,其他线程等待)

  • sleep()

    线程停止运行一段时间,让出CPU,将处于阻塞状态

    如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行

  • yield()

    让当前真该执行线程暂停,不是阻塞线程。而是将线程转入就绪状态

    如果调用了yield方法之后,没有其他等待执行的线程,这个时候当前线程就会马上恢复执行

  • setDaemon()

    可以将指定的线程设置成后台线程

    创建后台线程的线程结束时,后台线程也随之消亡

    只能在线程启动之前把他设为后台线程

  • interrupt()

    并没有直接中断线程,而是需要被中断线程自己处理(信号灯)

  • stop()

    结束线程,不推荐使用

线程同步

同步代码块锁

• synchronized (锁){ 同步代码 }

  1. 必须是引用数据类型,不能是基本数据类型

  2. 在同步代码块中可以改变同步监视器对象的值,不能改变其引用

  3. 尽量不要String和包装类Integer做同步监视器.如果使用了,只要保证代码块中不对其进行任何操作也没有关系

  4. 一般使用共享资源做同步监视器即可

  5. 也可以创建一个专门的同步监视器,没有任何业务含义

建议使用final修饰同步监视器

同步方法锁

• private synchronized void aa(int amt) {}

​ 使用synchronized修饰的方法就是同步方法,锁代表的就是this。

​ 注意:不推荐使用synchronized修饰run()方法

同步静态方法

方法使用static和synchronized同时修饰的方法成为同步静态方法,锁是类的字节码对象ti.getClass()

注意:同一个类new出的不同对象的类的字节码是相同的

线程同步 优点和缺点

· 优点:安全

· 缺点:效率低下 ,可能出现死锁

死锁

  • 多个线程共享多个资源
    ed修饰的方法就是同步方法,锁代表的就是this。

​ 注意:不推荐使用synchronized修饰run()方法

同步静态方法

方法使用static和synchronized同时修饰的方法成为同步静态方法,锁是类的字节码对象ti.getClass()

注意:同一个类new出的不同对象的类的字节码是相同的

线程同步 优点和缺点

· 优点:安全

· 缺点:效率低下 ,可能出现死锁

死锁

  • 多个线程共享多个资源
  • 多个线程都需要其他线程的资源,每个线程又不愿放弃自己的资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

~Amory

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

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

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

打赏作者

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

抵扣说明:

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

余额充值