线程 (续上)

2.3. Thread 常用的方法

2.3.1. 线程休眠方法--- sleep

sleep 线程的休眠方法 -------static void sleep(静态方法)

public class MyThread extends Thread{

    @Override
    public void run() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        for (int i = 0; i < 20; i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

2.3.2. yield 当前线程让出cpu-参与下次的竞争

当前正在执行的线程暂停执行,并允许其他线程获得执行的机会。具体来说,它会让出CPU时间片给其他线程,但并不保证一定会让出。

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++){
            Thread.yield();
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

2.3.3. join------加入当前线程上

插入的线程执行完毕后,当前线程才会执行。

当在一个线程中调用另一个线程的 join() 方法时,当前线程会被阻塞,直到被调用的线程执行完毕。这样可以确保在继续执行后续代码之前,被调用的线程已经完成了它的任务。

  public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread2 t2 = new MyThread2();
        t1.start();
        t2.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        for(int i = 0; i < 20; i++){
            System.out.println("main线程:" + i);
        }
    }
}

2.3.4. setDaemon()-----------设置线程为守护线程

当所有线程执行完毕后,守护线程也会终止。

JDK--默认就有一个守护线程.GC垃圾回收。

'public static void main(String[] args) {
        Mythread t1 = new Mythread();
        t1.setName("线程1");
        t1.setDaemon(true);
        t1.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("main线程:"+i);
        }
    }

其他方法:

  1. run(): 当线程被启动时,执行该方法中的代码。如果线程是使用 Runnable 接口创建的,则 run() 方法来源于该接口的实现。
  2. start(): 用于启动线程,会调用线程对象的 run() 方法。如果线程已经启动,再次调用 start() 会抛出 IllegalThreadStateException 异常。
  3. currentThread(): 返回对当前正在执行的线程对象的引用。这在需要获取当前线程信息或者对当前线程进行操作时非常有用。
  4. sleep(long millis) / sleep(long millis, int nanos): 让当前线程休眠指定的时间。第一个参数是以毫秒为单位,第二个参数是以纳秒为单位。在休眠期间,线程不丧失任何监视器的所有权。
  5. yield(): 提示调度程序当前线程愿意放弃处理器的使用,但调度程序可以忽略这个提示。通常用于实现线程之间的协作,让出 CPU 时间给其他线程。
  6. interrupt(): 用于中断线程的执行。如果线程处于阻塞状态(例如,通过调用 sleep() 方法),那么该线程的 interrupt() 方法会被调用,从而抛出 InterruptedException。
  7. join(): 等待指定线程终止。例如,在一个线程 A 中调用另一个线程 B 的 join() 方法,则线程 A 将进入阻塞状态,直到线程 B 运行结束。
  8. isAlive(): 检查线程是否仍然存活。如果线程已经启动且尚未结束,则返回 true。
  9. getName() / setName(String name): 获取或设置线程的名称。线程名称对于调试和监控非常有用。
  10. setPriority(int newPriority): 更改线程的优先级。优先级高的线程更可能得到执行。
  11. isInterrupted(): 测试线程是否已中断,返回布尔值。与 interrupted() 方法不同,这个方法不会清除中断状态。
  12. interrupted(): 测试当前线程是否已中断,并清除中断状态。如果连续两次调用这个方法,第二次调用将返回 false,除非当前线程在这两次调用之间再次被中断

2.4. 解决线程安全问题

2.4.1. 什么情况下会出现线程的安全问题?

当多个线程操作同一个资源时,则出现线程安全问题。

2.4.2. java如何解决线程安全问题

提供了两种方式:

第一种: 使用synchronized自动锁

第二种: 使用Lock手动锁。

使用锁相对于把原来的异步转换为同步操作。

使用synchronized自动锁 -------(它可以使用在方法上,也可以使用在代码块中。)

用法 1 代码块 : ---- (这里需要注意 参数对象需要是 同一个 )

synchronized(共享锁对象){
 //同步代码块。
}

用法 2 方法上 --- 直接在返回值类型 前加 synchronized

public class SellTickets implements Runnable{

    private Integer ticket = 100;
    @Override
    public  void run() {
        while (ticket > 0){
            sellTicket();
        }
    }
    public synchronized void sellTicket() {
        if(ticket > 0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "正在出售第" + (100-ticket) + "张票");
        }
    }
}

使用Lock手动锁

public class SellTicket2 implements Runnable{

    private Integer ticket = 10000;
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try {
                lock.lock();
                if(ticket > 0){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + (10000-ticket) + "张票");
                }else {
                    break;
                }
            } finally {
                lock.unlock();
            }
        }
    }
}

2.4.3. synchronized和lock区别

syn可以使用代码块和方法。自动加锁和释放锁。不会出现死锁问题。

lock它只能使用在代码块中。需要手动加锁和释放锁。如果不释放锁,死锁问题。灵活。它的释放锁必须放在finally.

2.5. 线程的死锁问题

线程A拥有锁资源a,希望获取锁资源b,线程B拥有锁资源b,希望获取锁资源a。 两个线程互相拥有对方希望获取的锁资源。可能会出现程序堵塞。从而造成死锁。

解决办法

  1. 不要使用锁嵌套。
  2. 设置超时时间。--Lock类中tryLock.
  3. 使用安全java.util.concurrent下的类。

2.6. 线程通信 ---- 通过调用不同的方法相互转换

主要用到 wait() notify() 方法

wait()方法使当前线程进入等待状态,直到其他线程调用同一个对象的notify()

notify()方法用于唤醒在此对象监视器上等待的单个线程。如果有多个线程正在等待,则随机选择一个线程唤醒。需要注意的是,调用notify()方法并不会立即释放锁,而是在synchronized代码块或方法执行完毕后才会真正释放锁。

2.7. 线程状态

NEW,====新建状态。

RUNNABLE,===>就绪状态和运行状态

BLOCKED,===>堵塞状态

WAITING,====>等待状态

TIMED_WAITING,===>时间等待

TERMINATED;===终止。

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值