0228-线程中的属性和方法、同步锁

文章详细阐述了Java线程的四种状态:初始、可运行、运行和终止,并介绍了线程的name属性、currentThread()方法、sleep()方法。此外,还讨论了线程的阻塞状态和ThreadLocal类的使用。对于线程不安全问题,文章提出了线程同步的概念,特别是通过synchronized关键字实现的同步锁机制,并通过存款和取款任务的例子说明了同步在多线程编程中的应用。
摘要由CSDN通过智能技术生成
  • 线程状态

在这里插入图片描述
初始状态:

一个刚被创建好的线程对象,就是初始状态的对象。

Thread t = new Thread(new Runnable02());

当前新创建的 t 线程对象就是初始状态。

可运行状态:

一个线程想要运行必须先抢到 CPU。启动与运行是不同的概念。

当一个线程对象调用了 start() 方法启动了,但还没有抢到 CPU 时,就是一个可运行状态

可运行状态的线程对象只做一件事:抢 CPU。

运行状态:

一个抢到 CPU 正在执行的线程对象。称为运行状态。

当一个运行状态的线程对象,CPU 时间到期要转换为 可运行状态。

终止状态:

一个执行完成 run() 方法的线程对象,就是终止状态。


  • 线程中的常用属性和方法

name 属性:

用来表示一个线程对象的名称。可以在创建线程对象时指定。也可以通过方法指定。

public class NameTest {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnbale02(),"线程1");

        System.out.println(t.getName());
    }
}

currentThread() :

Thread 类的静态方法,动态获取当前执行的线程对象。

public static native Thread currentThread()
public class Runnbale02 implements Runnable{
    @Override
    public void run() {
        for(int i = 1;i<=10;i++) {
        	//通过Thread.currentThread()方法获取当前的线程对象
        	//通过.getName()来获取线程对象的名称
            String name = Thread.currentThread().getName();
            System.out.println(name+"-"+ i+":000");
        }
    }
}

sleep() 方法:

---------- 休眠方法。

哪一个线程运行过程中,遇到 sleep 方法。哪一个线程自己休眠。

public static native void sleep(long millis) throws InterruptedException
public class Runnbale02 implements Runnable{
    @Override
    public void run() {
        for(int i = 1;i<=100;i++) {
            String name = Thread.currentThread().getName();
            try {
            	//通过Thread.sleep()方法进行休眠,并指定休眠时间;单位为毫秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name+"-"+ i+":000");
        }
    }
}

  • 阻塞状态

线程对象运行过程中,出现以下情况:

  1. 等待 IO。----做标准输入时,用户需要从控制台输入数据时。
  2. sleep方法。---- 当前线程休眠。

当线程遇到以上两种情况时,会进入阻塞状态,并会释放CPU
在这里插入图片描述


  • 本地线程对象:ThreadLocal 类

本地线程对象其实是一个容器,而且是一个只能保存一个数据的容器对象。

这个容器在每一个不同的线程中,都有一份自己的实例。

每一个线程对象都使用自己的 ThreadLocal 类的实例。

当出现多个线程时,每一个线程中都有一个自己使用的 ThreadLocal 对象。

常用方法:

public static void main(String[] args) {
    ThreadLocal<String> local = new ThreadLocal<>();
	//使用get、set方法来设置和取
    local.set("peter");
    //因为只存放一个数据,所以get方法没有参数
    String s = local.get();
    System.out.println(s);
}

  • 线程不安全

线程不安全是指:多个线程在操作数据时,数据不正确的情况。

线程不安全的几个条件:

  1. 多个线程 ----- 多线程
  2. 同时操作 ----- 并发
  3. 同一个数据 ----- 临界资源
  4. 破坏了 不可分割的操作时 ----- 原子性

当以上的情况发生时,就有可能造成数据的不一致。这种情况就称线程不安全。

当多线程并发操作临界资源时,破坏了其原子性操作时,就可能造成数据不一致的问题。
解决方法:线程同步


  • 线程同步

线程同步:多个线程以串行的方式执行。

而,一起并发执行的方式则为:异步。

串行的方式执行:是针对对临界资源的操作部分以串行的方式操作。

同步锁 synchronized:

使用同步锁,来保证临界资源的原子性操作不被分割。

在执行原子性操作之前,先获取同步锁对象。之后再执行原子性代码。只有原子性代码执行完成之后。我们才会释放同步锁对象。

特殊注意:只有使用同一个同步锁的多个线程,才会以串行的方式执行。

必须要保证,多个线程使用的是同一个锁对象。才能叫多个线程的同步。

PS:一般情况下,临界资源做为锁对象更合适。


同步锁的使用方式:

synchronized(锁对象){
	//原子性操作代码;
}

存款任务类:

public class DepositRunnable implements Runnable{
	//任务类需和业务层对接
    private AcountService service = new AcountService();
    private Acount acount;
    private Double money;
    public DepositRunnable(Acount acount, Double money) {
        this.acount = acount;
        this.money = money;
    }
    @Override
    public void run() {
    	//此处使用acount作为锁对象
        synchronized (acount) {
            System.out.println(Thread.currentThread().getName() + "-存款任务开始!");
            service.deposit(acount, money);
            System.out.println(Thread.currentThread().getName() + "-存款成功!" + acount.getMoney());
            System.out.println(Thread.currentThread().getName() + "-存款任务结束!");
        }
    }
}

取款任务类:

public class DrawRunnable implements Runnable {
    private AcountService service = new AcountService();
    private Acount acount;
    private Double money;

    public DrawRunnable(Acount acount, Double money) {
        this.acount = acount;
        this.money = money;
    }

    @Override
    public void run() {
    	//使用同步锁:
        synchronized (acount) {
            System.out.println(Thread.currentThread().getName() + "-取款开始!");
            try {
                service.draw(acount, money);
                System.out.println(Thread.currentThread().getName() + "-取款成功!" + acount.getMoney());
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(Thread.currentThread().getName() + "-" + e.getMessage() + "取款失败!" + acount.getMoney());
            }
            System.out.println(Thread.currentThread().getName() + "-取款结束!");
        }
    }
}

测试类中:

public class Test {
    public static void main(String[] args) {
        Acount acount = new Acount(10000.0);//临界资源
		//创建任务对象:
        DepositRunnable depositRunnable01 = new DepositRunnable(acount,10000.0);
        DepositRunnable depositRunnable02 = new DepositRunnable(acount,2000.0);

        DrawRunnable drawRunnable01 = new DrawRunnable(acount,5000.0);
        DrawRunnable drawRunnable02 = new DrawRunnable(acount,5000.0);
		//创建线程对象并传入参数:任务类和名称
        Thread t1 = new Thread(depositRunnable01,"自己");
        Thread t2 = new Thread(depositRunnable02,"父母");
        Thread t3 = new Thread(drawRunnable01,"女儿");
        Thread t4 = new Thread(drawRunnable02,"老婆");
		//线程启动:
        t1.start();
        t2.start();
        t3.start();
        t4.start();
     }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值