Java基础-线程

并行:多个cpu同时执行多个任务,cpu并行

并发:一个cpu同时执行多个任务,进程并发

程序:是一段静态的代码

进程:是程序的一次动态运行过程,对应从代码加载、执行到执行完成的整个过程。进程是系统资源调度的最小单位进程拥有独立的内存单元(代码段、数据段)

线程:线程是更小的执行单位,一个进程在运行过程中可以创建多个线程。线程开销较小,是cpu资源分配的最小单位多个线程共享进程的内存空间,但线程独立拥有栈空间和寄存器组

1、线程创建方式1-继承Thread类

步骤描述:创建类继承类Thread->重写run方法,定义线程需要进行的操作->创建该类(Thread类的子类)的对象->对象调用start方法(启用当前线程,调用当前线程的run方法执行操作)。代码演示如下:

public class ThreadTest {
    public static void main(String[] args) {
        //2、线程调用
        TThread tThread = new TThread();
        tThread.start();

    }

}
//继承Thread类的方式创建线程
//1、定义线程类
class TThread extends Thread{
    @Override
    public void run() {
        System.out.println("线程1创建啦!!!");
    }
}

java8之后,也可以使用lambda表达式创建线程

 new Thread(()->{
            System.out.println("线程创建了");
        }).start();
    }

2、线程创建方式2->实现Runnable接口

步骤描述:创建类实现Runnable接口->该类实现抽象方法run->创建实现类的对象1->将此对象1作为参数传递给Thread类的构造器中创建Thread类的对象2->通过Thread类的该对象2调用start方法。代码演示如下:

public class ThreadTest {
    public static void main(String[] args) {
        TThhread2 t2 = new TThhread2();//2
        Thread thread2 = new Thread(t2);//3
        thread2.start();//4

    }

}
//实现Runnable接口
//1、定义线程类
class TThhread2 implements  Runnable{

    @Override
    public void run() {
        System.out.println("线程3创建成功啦!!!!!!");
    }
}

3、线程创建方式3->实现Callable接口

步骤描述:类实现Callable接口->该类实现call方法(可有返回值)->创建实现类的对象1->将此对象作为参数传递到FutureTask的构造器中创建对象2->将对象2作为参数传递到Thread类的构造器中,创建对象3->对象3调用start方法。

class TThread3 implements Callable{

    @Override
    public Object call() throws Exception {
        System.out.println("线程创建");
        return null;
    }
}

public class ThreadTest {
    public static void main(String[] args) {

        TThread3 tThread3 = new TThread3();
        FutureTask task = new FutureTask<>(tThread3);
        new Thread(task).start();
    }

    }

4、方式4->使用线程池

可创建多个线程放入线程池中,使用线程时直接从线程池中获取,使用完放回线程池,可有效提高响应速度,降低资源消耗,便于线程管理。使用步骤描述:创建线程池->执行指定线程的操作,提供Runnable/Callable对象->关闭连接池,使用示例如下:

//使用线程池创建对象
        ExecutorService executor=Executors.newFixedThreadPool(5);//创建固定大小为5的线程池
            /*
            常用线程池还有
            Executors.newCachedThreadPool(); //可缓冲线程池
            Executors.newSingleThreadExecutor();//单线程贤线程池
             * */
        Thread t = new Thread(() -> {
            System.out.println("线程1创建");

        });
        Thread t1 = new Thread(() -> {
            System.out.println("线程2创建");

        });
        //将线程放入池中,并执行线程的操作
        executor.execute(t);
        executor.execute(t1);   //当线程创建方式为callable时,此处使用submit()
        //关闭连接池
        executor.shutdown(); 
    }

ThreadPoolExecutor extends AbstractExecutorService implements ExecutorService

 线程池真正的实现类是 ThreadPoolExecutor

上图中的构造器只涉及所有必需指定的参数,完整参数的构造器结构如下

下面将介绍涉及的参数及其含义:

int corePoolSize(必需参数):线程池中的核心线程数,默认情况下核心线程一直存活

int maximumPoolSize(必需):线程池能够容纳的最大线程数

long keepAliveTime(必需):存活时间,当核心线程的空闲时间超过该时常时被回收

TimeUnit unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。非空对象,但不是必须参数。

BlockingQueue<Runnable> workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中,其采用阻塞队列实现。非空

ThreadFactory threadFactory(可选参数): 用于指定为线程池创建新线程的方式;非空

RejectedExecutionHandler handler(可选):拒绝策略,当达到最大线程数时需要执行的饱和策略。非空

且各参数需满足如下条件:
 corePoolSize >= 0

keepAliveTime >= 0

maximumPoolSize >0

maximumPoolSize >= corePoolSize

 workQueue 、 threadFactory 、handler 对象不能为 null

使用示例:

关于参数 workQueue 、 threadFactory 、handler详解见文章:

线程池的参数详解_ITsOK6的博客-CSDN博客

5、线程常用方法

public synchronized void start() ;//启动当前线程并执行线程run方法定义的操作。
public void run();//定义线程执行的操作,执行完成之后线程进入死亡状态
public final synchronized void setName(String name);//设置当前线程的名字
public final String getName();//返回当前线程名
public static native Thread currentThread();//返回当前使用cpu的线程
public static native void yield();//当前线程释放对cpu的占用
public final void join();//当前线程(调用该方法)抢先占用cpu执行操作,先于正在执行的线程执行(线程联合)
public final void stop();//强制结束当前线程的生命周期,一般情况下不建议采用
public static native void sleep(long millis);//当前线程进入阻塞状态,时间为millis
public final native boolean isAlive();//判断当前线程是否存活

6、线程的生命周期

Thread类的内部枚举类State中定义了线程的几种生命状态,线程状态存储在threadStatus属性中。

线程有新建、运行、阻塞、等待、超时等待和死亡6种状态。转换关系如下:

7、线程同步问题

 多个线程对同一段代码进行操作时,需要考虑线程安全问题,当前线程操作时其他线程只能等待。借助以下方式实现线程同步

1、同步代码块

即使用synchronizd关键字,将操作共享数据的代码放在代码块中,实现线程同步控制,但操作代码块时同一时间只允许单个线程进行操作,效率不高。

public class synchronizedTest {
    public static void main(String[] args) {
        new SynThread("A").start();
        new SynThread("B").start();
    }
}
//定义线程类
class SynThread extends Thread{
    //共享数据
  static  int count=0;
    public SynThread(String name){
        super(name);
    }
    @Override
    public void run() {
        //共享操作,对变量count进行加一操作
        //使用同步代码块进行多线程同步
        /*
        格式 synchronized (同步锁/同步监视器)-->任何类的对象都可充当锁
        {
        同步代码块
        }
         */

        synchronized (SynThread.class){
            for (int i = 0; i <5 ; i++) {
                System.out.println(currentThread().getName()+"当前count="+count++);

            }
        }
    }
}

运行结果如下:

不加锁时运行结果如下:

2、同步方法

 如果操作数据共享数据是一个方法,此方法可声明为同步方法。此时的同步监视器无需显示声明,如果为静态同步方法,则同步监视器为当前类本身;如果为非静态方法,同步监视器为this;锁的对象不同,锁粒度不同,执行性能也不同。

权限修饰符 synchronized 返回值类型  方法名(参数列表){

方法体

}

3、Lock锁

lock锁为java5之后的新特性,在使用时需要显式加锁和解锁,使用示例如下:

class TThread2 implements  Runnable{
    int count=0;
    //实例化ReentrantLock
    ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        //加锁lock()
        lock.lock();
        for (int i = 0; i <5 ; i++) {
            System.out.println(currentThread().getName()+"当前count="+count++);
             }
        //释放锁unlock()
        lock.unlock();


    }
}
public class synchronizedTest {
    public static void main(String[] args) {
        TThread2 tThread2 = new TThread2();
        new Thread(tThread2,"C").start();
        new Thread(tThread2,"D").start();



    }
}

运行结果如下图

 4、synchronized和lock的区别

  • 使用方式不同

synchronized可作用在静态方法、示例方法和代码块上,是一种隐式锁,无需显式获取和释放;Lock是一种显式锁,需要调用其内部方法显式地获取和释放锁,提供了更好的灵活性,在这种同步方式下可通过condition实现线程通信。

  • 功能特性不同

synchronized是早期api,java5之后引入locc在设计上弥补synchronized的不足,这些新特性包括:lock可中断、非阻塞、可超时地获取锁。未获得锁时返回false,反之返回true。

  • 实现机制不同

synchronized底层采用java对象头存储信息,并支持锁升级;

lock实现类基于AQS(是一个双向链表)实现的,AQS(Abstract QueueSynchronizer)队列同步器,用来构造锁的框架,AQS内部定义了一个FIFO队列实现线程同步,还定义同步状态存储锁的信息。

  • 通信api

synchronized: wait(),notify()/notifyAll();(同步监视器调用)

lock: await(),signal()/signalAll():(lock.newCondition()对象调用)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值