Java多线程

Java多线程

1.什么是多线程

打开任务管理器我们可以看到许多进程,一个应用程序一启动就可以是一个进程。线程是进程里面的子任务,我们学Java都配置过环境变量,那个”系统属性“页面 就很烦啊,一旦打开了 ”环境变量“,就必须要关闭或者确认后才能重新操作 ”系统属性“,否则不但无法操作而且 ”环境变量“ 的框还会一闪一闪的。这就是单线程,只允许单线操作。
在这里插入图片描述
再举个多线程的例子,玩扫雷游戏的时候,只要开始操作,那个计时器就会持续不断计数。也就是说我们的操作和计时器是分为两个线程运行的。

2.实现多线程的两种方式

  1. 继承Thread,重新run方法
public class demo1 extends Thread{
    @Override
    public void run() {
        for(int i =0;i<10;i++){
            System.out.println(getName()+i);//getName是继承自父类
        }
    }

    public static void main(String[] args) {
        demo1 a = new demo1();
        demo1 b = new demo1();
        //demo1 c = new demo1();
        a.setName("路飞");
        b.setName("索隆");
        
        //获取当前线程名,当前是主线程,也就是main
        System.out.println(Thread.currentThread().getName());

        //设置主线程名称(当前线程)
        Thread.currentThread().setName("罗杰");
        a.start();
        b.start();
        //c.start();
        
        //主线程任务
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

介绍部分函数:

try {
    Thread.sleep(1000);//运行后休息1秒,需要捕获或抛出异常
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

//通过有参构造直接给线程赋值,无需setName
public demo1(String name){
        super(name);
    }
demo1 a = new demo1("路飞");
demo1 b = new demo1("索隆");

//获取线程的优先级,默认为5
System.out.println(a.getPriority());
System.out.println(b.getPriority());

//设置线程优先级
c.setPriority(10);//1-10数字
b.setPriority(Thread.MAX_PRIORITY);//最大10
a.setPriority(Thread.MIN_PRIORITY);//最小1

  1. 实现Runnable接口
public class demo2 implements Runnable{
    /**
     * 实现Runnable接口的好处:
     *      1.避免单继承的局限性
     *      2.适合相同的代码去处理同一个资源,体现面向对象的思想
     */
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+i);
        }
    }

    public static void main(String[] args) {
        demo2 aa = new demo2();
        Thread a = new Thread(aa,"路飞");
        Thread b = new Thread(aa,"索隆");
        a.start();
        b.start();
    }
}

3.守护线程

当线程中全部都是守护线程,jvm退出,因为有延迟,所以还会往后执行一丢丢的时间。

a.setDaemon(true);
b.setDaemon(true);
c.setDaemon(true);

举个例子,我们把子线程都设为守护线程,一旦主线程先执行结束,子线程再执行短暂时间后立即结束。

4.线程安全

在多线程中一旦共享数据且线程中对该数据进行了处理,就会出现线程安全的问题,当一个线程刚要输出共享数据时,另一个线程抢到了cpu执行权先对数据进行了修改,那第一个线程中的数据就发生了变化。
提供一个情景:a线程有一个if语句,它成功进入if语句后,b线程抢到了执行权,修改了共享数据,使其不满足if,当执行权回到a后,数据已经不满足了,但它早已通过了if。

解决线程安全的三种方式(都是基于synchronized):

  1. 使用synchronized代码块,用synchronized将语句块框住,要传入任意对象,注意每次都要传入同一个对象,这才表明是同一个锁,否则每次执行又是新锁根本锁不住。我没给例子所以说明它用的少。
  2. 使用同步方法:
    分为静态和动态方法
 public static synchronized void sellTickets(){
       //这是静态方法的例子,
       //相当于synchronized(类名.class),也就是synchronized代码块,传入的锁是类名.class
    }
    public synchronized void sellTicket(){
    	//这是动态方法的例子
    	//相当于synchronized(this),也就是synchronized代码块,传入的锁是当前对象,就是this
    }

3.使用Lock类

private Lock lock  = new ReentrantLock();//先在类中定义一个锁
lock.lock();//加锁
lock.unlock();//解锁
//由于程序可能出现异常导致解锁的步骤未执行就已经出问题
//所以一般使用try/finally语句块,try中加锁,finally中解锁

5.等待唤醒

使用wait()停止当前线程,注意它需要在synchronized内使用,比如在同步方法内使用;
使用notifyAll()唤醒全部等待线程;
举个使用场景:买卖流程,当商品卖完后就要让消费者的线程进入等待状态,等到生产者生产完一批商品后再唤醒消费者的线程。
当商品多到一定的阈值,就要让生产者进入等待状态,等待消费者消费了一定的商品后再唤醒生产者。

6.总结

以上就是线程的主要内容,线程在软件的开发中是十分常见的,线程锁和数据库的锁都需要谨慎使用,它们既能保证线程和数据安全,同时也会降低运行效率,所以一定要慎之又慎。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hfhua

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

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

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

打赏作者

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

抵扣说明:

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

余额充值