并发,多线程,同步,线程池的使用

并发与并行

并发:指的是两个事件或多个事件在同一时间段内发生。

并行:指的是两个事件或多个事件在同一时间点发生。

进程与线程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建,运行到消亡的过程。

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称为多线程程序。

程序运行后至少有一个进程,一个进程中可以包含多个线程。

线程的调度

分时调度:是指所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。

抢占式调度:是指优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个线程(线程随机性),java使用的为抢占式调度。

主线程(main线程)

主线程:执行主方法的线程。

单线程程序:java程序中只有一个线程,执行从main方法开始,从上到下依次执行。

单线程程序的弊端:主线程中出现异常,后续代码不会继续执行。

多线程原理

单线程程序执行时,只在一个栈空间内入栈出栈,所以发生异常后,后续代码不再执行。

而多线程程序执行时,每调用start()方法一次,就新开辟一个栈空间,这个栈空间和main方法的栈空间互不干扰,优先级相同时cpu随机选择一个线程执行。

创建多线程程序的方式:

继承Thread类

该类存在于java.lang包中。

实现步骤:
1.创建一个Thread类的子类;
2.在Thread类的子类中重写Thread类中的run()方法,设置线程任务;
3.创建Thread类的子类的对象;
4.调用Thread类中的方法start()方法,开启新的线程,执行run()方法。

注意:
1.执行start()方法后,jvm调用该线程的run方法,两个线程并发运行,一个是main线程,一个是执行run方法后新创建的线程。
2.多次启动一个线程是非法的,特别是当线程已经结束执行后,不能再重新启动。
3.java程序属于抢占式调度,哪个线程的优先级高,哪个线程优先执行,同一个优先级,随机选择一个执行。
4.可以通过Thread对象调用setPriority()方法设置线程的优先级。参数范围为1-9,参数越大优先级越高。

实现Runnable接口

推荐使用该方法。
该接口存在于java.lang包中。

实现步骤:
1.创建一个Runnable接口的实现类;
2.实现类重写Runnable接口的抽象方法run(),设置线程的任务;
3.创建一个Runnable接口的实现类对象;
4.创建Thread类对象,把Runnable接口的实现类对象作为参数传递给Thread类的构造方法;
5.调用Thread类的start方法,开启新线程。

两种方法的区别

1.使用继承Thread类的方法有局限性,即java的单继承。如果继承了Thread类,则后续无法继承其他类。
但是如果采用实现Runnable接口的方法,则可以避免该局限性,实现接口的同时还可以继承其他类。

2.实现Runnable接口的方法,将设置线程任务和开启新线程进行了分离,即在重写接口的run方法时设置线程任务,对Thread类构造函数传参和执行start方法时开启新线程。

线程安全问题

多线程程序访问了共享的数据,会产生线程安全问题。

线程安全问题产生的原理

多个线程同时开始执行时,如果访问同一个共享的资源,同时修改数据,就会出现预料之外的效果。所以我们要使一个线程在访问共享资源时,无论是否进入阻塞状态,释放cpu资源与否,其他线程都等待,已解决线程安全问题。

解决线程安全问题

同步代码块

语法:
synchronized(锁对象){
可能会出现安全问题的代码(访问了共享数据的代码)
}

注意:
1.代码块中的锁对象,可以使用任意的对象
2.必须保证多个线程使用的锁对象是同一个
3.锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行。

同步方法

语法:
修饰符 synchronized 返回值类型 方法名(参数列表){
可能产生线程安全问题的代码
}

修饰符 返回值类型 方法名(参数列表){
synchronized(锁对象){
可能产生线程安全问题的代码
}
}

静态同步方法

语法:
修饰符 static synchronized 返回值类型 方法名(参数列表){
可能产生线程安全问题的代码
}

修饰符 static 返回值类型 方法名(参数列表){
synchronized(锁对象){
可能产生线程安全问题的代码
}
}

注意:
1.锁对象是谁?
对于非静态方法,锁对象是this。
对于静态方法,因为this是对象创建后才存在,所以锁对象是(类名.class)。

使用Lock接口

该接口存在于java.util.concurrent包中。

Lock接口提供了比synchronized方法和语句更广泛先进的锁操作。

接口中常用方法:
1.void lock() //获取锁
2.void unlock() //释放锁

使用步骤:
1.导包;
2.在成员位置创建一个ReentrantLock对象(也可以使用多态写法);
3.在可能会出现安全问题的代码之前通过对象调用Lock接口中的方法lock()获取锁。
4.在可能会出现安全问题的代码之后通过对象调用Lock接口中的方法unlock()释放锁。
5.如果有异常可以结合try-catch-finally语句,将释放锁语句放在finally代码块中,可以提高程序效率。

线程池的使用

线程结束后无法重新开启,使用线程池可以达到线程复用的效果。

线程池工厂类:java.util.concurrent.Executors:用来生成线程池

该类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池。
参数:int nThreads:创建线程池中包含的线程数量
返回值:ExecutorService接口的实现类对象,可以使用ExecutorService接口接收

使用步骤:
1.使用线程池的工厂类Executors里提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池的接口ExecutorService。
2.创建一个Runnable接口的实现类,重写run方法,设置线程任务。
3.调用ExecutorService接口中的方法submit,参数传递这个实现类,开启线程,执行run方法。
//4.调用ExecutorService接口中的方法shutdown销毁线程池。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值