Java中线程复习

本文详细介绍了Java中的线程概念,包括线程的创建方式(继承Thread和实现Runnable)、线程生命周期、优先级设置、线程同步与Lock的使用,以及避免死锁的方法。此外,还探讨了线程通信和Callable接口在提供更强大功能方面的应用。
摘要由CSDN通过智能技术生成

什么是线程

进程:是操作系统进行资源分配的最小单位。
线程:是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元,隶属于进程。

如何创建线程

  1. 继承Thread类,本质上也是实现Runnable接口
public class MyThread extends Thread {
		@Override  //重写Run方法
		public void run() {
		}
}
// 调用
MyThread thread = new MyThread();
thread.start() //启动线程时,执行Run()方法
  1. 实现Runnable接口
定义:
public class MyThread implements Runnable{
	@Override
	public void run() {
	}
}
//调用 
MyThread mythread = new MyThread();

//创建一个线程作为外壳,将r包起来,
Thread thread = new Thread(mythread);
thread.start();

继承方式和实现方式的联系与区别

区别:

继承Thread:线程代码存放在Thread子类MyThread的Run方法中
实现Runnable:存放在接口的子类的run方法中

实现Runnable的好处

  • 避免单线程的局限性。如果一个类已经继承了其他类,就不能再继承Thead类来实现多线程。
  • Runnable接口只有一个抽象方法,不需要再继承Thread类的构造函数和其他方法,代码实现更加简洁。
  • 可以将任务逻辑与线程调度逻辑分离,使得代码更加模块化,方便扩展和重用。
public class MyThread implements Runnable{
	//任务逻辑
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("MyThread:"+i);
        }
    }
}
public class Test {
    public static void main(String[] args) {

        //创建一个线程中需要执行的任务,并没有真正的创建线程
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        //启动线程
        thread.start();
		//主线程逻辑
        for (int i = 0; i < 1000; i++) {
            System.out.println("main:"+i);
        }
    }
}


输出结果可以看到主线程和子线程交替执行,展现了Runnable接口实现多线程任务的效果。

Thread类中的方法

常用方法

方法原型说明
void start()启动线程
final String getName()返回线程的名称
final void setPriority(int newPriority)设置线程的优先级
final int getPriority()返回线程的优先级
final void join()等待线程终止
static Thread currentThread()返回对当前正在执行的线程对象的引用
static void sleep(long millis)让当前正在执行的线程休眠(暂停执行),休眠时间由milli s(毫秒)指定
yield()线程让步

线程优先级

计算机只有一个CPU,各个线程轮流获得使用权,优先级较高的线程有更多机会获得CPU的机会。
一般情况下,线程的默认优先级是5,可以通过setPriority()来设置优先级

调度方法

同优先级使用时间片策略,是先进先出形成队列。
高优先级使用抢占式策略

线程生命周期

mi

  • 新建状态:使用new关键字和Thread类或其子类创建一个线程对象后,该线程对象就处于新建状态。保持直到程序start()这个线程。

  • 就绪状态:当线程对象调用了start()方法之后,就到了就绪状态。就绪状态处于就绪队列中,然后等待JVM里线程调度器调用。

  • 运行状态:就绪状态获取到CPU资源就可以执行run()方法,此时便是运行状态。

  • 阻塞状态:如果一个线程执行了sleep(睡眠),挂起等方法,失去所占用的资源后,就会从运行状态变为阻塞状态。睡眠时间已到,或者重新获取资源后,可进入就绪状态。

  • 死亡状态:一个线程执行完成或其他终止条件发生时,就切换到死亡状态。

多线程

定义:多线程是指程序中包含多个执行单元,可以并发执行。
用处:程序需要同时执行俩个或多个任务。
优点:提高CPU的利用率,,提高程序的响应,
缺点:线程也是程序,线程越多所占有的内存就越多。多线程需要协调和管理,所以需要CPU跟踪线程。

线程同步

并发与并行

并发:俩个或多个程序在同一时间间隔内发生。宏观上是同时发生的,微观上是轮流交替发生的。
并行:俩个或多个程序在同一时刻发生。

单核CPU同一时刻只能执行一个程序,只能并发执行。
多核CPU同一时刻可以同时执行多个程序,并行执行。

多线程同步

多线程同时读写到一份共享资源时,可能会引发冲突,所以出现线程同步机制。
同步就是 排队+锁
几个线程之间要排队,一个一个对资源进行操作,而不是同时操作。
为了保证数据被正确访问,加入锁。
确保一个时间点只有一个线程访问共享资源。可以给共享资源加入锁。

//使用synchronized(同步锁)关键字同步方法或代码块。
synchronized (同步锁){
	// 需要被同步的代码;
}

//synchronized还可以放在方法声明中,表示整个方法,为同步方法。
public synchronized void show (String name){
	// 需要被同步的代码;
}

同步锁可以是任何对象,但必须是唯一的,保证多线程获得的师同一个对象(充当锁标记)。

同步执行过程

  1. 第一个线程访问,锁定同步对象,执行其中的代码
  2. 第二个线程访问,发现同步对象被锁定,无法访问。
  3. 第一个线程执行完毕,释放同步对象。
  4. 第二个线程访问,发现同步对象没有锁,然后锁定并访问。

Lock锁

一个线程持有锁会导致其他需要此锁的线程挂起。在多线程竞争下,加锁,释放锁会导致较多的上下文切换和调度延时,引起性能问题。
java.util.concurrent.locks.Lock接口是控制多个线程对共享资源访问的工具。
每次只能有一个线程对Lock对象加锁,线程开始访问共享资源前应该获得lock对象

 Lock lock = new ReentrantLock();
 lock.lock();//使用开始前加锁
 此处是对共享资源的访问。
 lock.unlock();//使用完毕后必须释放锁

线程死锁

在并发环境下,各进程因为资源竞争而造成的相互等待对方手里的资源,造成线程阻塞,都无法向前推进的现象,就是死锁。
什么是死锁,死锁产生的必要条件,如何避免锁

线程通信

指的是线程之间的相互作用。
三个方法

.wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
.notify一旦执行此方法,就会唤醒被wait的一个线程。有多个线程被wait,唤醒优先级最高的。
.notifyAll一旦执行此方法,就会唤醒所有被wait的线程。

.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。

新增创建线程方式

实现Callable接口与使用Runnable相比,Callable功能更强大些。
• 相比run()方法,可以有返回值
• 方法可以抛出异常
• 支持泛型的返回值
• 需要借助FutureTask类,获取返回结果

public class Sum implements Callable<Integer> {
    int sum=0;
    @Override
    public Integer call() throws Exception {
        for (int i = 0; i <= 10; i++) {
            sum+=i;
        }
        return  sum;
    }
}
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Sum sum = new Sum();
        //接收任务
        FutureTask<Integer> futureTask = new FutureTask<>(sum);

        Thread thread = new Thread(futureTask);//创建次任务的线程
        thread.start();

        Integer s = futureTask.get();//获取线程中的返回值
        System.out.println(s); // 打印结果55
    }
}
  • 52
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值