多线程与多进程
多线程的创建
常用方法
- void start():启动线程,执行run()
- run():线程启动后执行
- String getName():返回线程名称
- void setName(String name):设置该线程名称
- static Thread currentThread():返回当前线程。在Thread子类中就是this,通常用于主线程和Runnable实现类
- static void yield():线程让步。其实就是
线程异步 - join():线程并发堵塞
- static void sleep(long millis):指定单位为ms,让线程在指定时间内交出CPU控制权,时间到后才获得CPU控制权。
类似于python中的await - stop():不保留任何未处理数据的强制关停线程
- boolean isAlive():bool判断线程是否存活
方式一:继承于Thread类
- 创建一个继承于Thread类的子类
- 重写Thread类的run()
- 创建Thread类的子类的对象
- 通过此对象调用start()
class MyThread extends Thread{
// 重修Thread的run
@Override
public void run(){
// 多线程执行体
System.out.println("多线程run成功");
}
}
class TreadTest{
public static void main(String[] args){
// 创建Thread类的子类的对象
MyThread t1 = new MyThread();
// 调用start,多线程开启
t1.start();
}
}
方式二:实现Runnable接口
- 定义子类,实现Runnable接口。
- 子类中重写Runnable接口中的run方法。
- 通过Thread类含参构造器创建线程对象。
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
- 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
区别
| 继承Thread | 实现Runnable |
|---|---|
| 线程代码存放Thread子类run方法中 | 线程代码存在接口的子类的run方法 |
实现方式的好处
- 避免了单继承的局限性
- 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线 程来处理同一份资源。
线程优先级
调度策略
- 时间片:“拉链图式”
- 抢占式:优先级高的线程,优先获得cpu的控制权
Java的调度方法
- 同优先级默认组成队列,使用时间片策略
- 对高优先级,优先使用抢占式
优先级等级
MAX_PRIORITY:10
MIN _PRIORITY:1
NORM_PRIORITY:5
涉及的方法
getPriority():返回线程优先值setPriority(int newPriority):改变线程的优先级
补充
-
线程创建时继承父线程的优先级
-
低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
-
Java中的线程分为两类:一种是守护线程,一种是用户线程
守护线程是用来服务用户线程的,通过在
start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。两者的唯一的区别是判断JVM何时离开
线程的生命周期
新建-就绪-运行->堵塞?->死亡并回收

线程同步 join
对于一些异步操作可能会脏库的操作,进行同步并发
多个线程执行的不确定性引起执行结果的不稳定
多个线程对账本的共享,会造成操作的不完整性,会破坏数据。
防止新线程溢出
class TicketDemo{
public static void main(String[] args){
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
t1.setName("t1窗口");
t2.setName("t2窗口");
t3.setName("t3窗口");
t1.start();
t2.start();
t3.start();
}
}
Synchronized的使用方法
- 方式一
synchronized(对象){
// 需要同步的代码
}
- 方式二
public synchronized void show (String name){
// 需要同步的代码
}
-
注意:
必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就 无法保证共享资源的安全
一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方 法共用同一把锁(this),同步代码块(指定需谨慎)
锁
死锁 DeadLock.java
- 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃 自己需要的同步资源,就形成了线程的死锁
- 出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于 阻塞状态,无法继续
解决方法
- 专门的算法、原则
- 尽量减少同步资源的定义
- 尽量避免嵌套同步
// 线程死锁同步
public class DeadLockTest {
public static void main(String[] args) {
final StringBuffer s1 = new StringBuffer();
final StringBuffer s2 = new StringBuffer();
new Thread() {
public void run() {
synchronized (s1) {
s2.append("A");
synchronized (s2) {
s2.append("B");
System.out.print(s1);
System.out.print(s2);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized (s2) {
s2.append("C");
synchronized (s1) {
s1.append("D");
System.out.print(s2);
System.out.print(s1);
}
}
}
}.start();
}
}
锁的释放
- 当前线程的同步方法、同步代码块执行结束
- 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、 该方法的继续执行
- 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导 致异常结束
- 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线 程暂停,并释放锁
不释放的锁
- 线程执行同步代码块或同步方法时,程序调用
Thread.sleep()、Thread.yield()方法暂停当前线程的执行 - 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程 挂起,该线程不会释放锁(同步监视器)
- 应尽量避免使用
suspend()和resume()来控制线程
单例设计模式之懒汉式(线程安全)
class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
// 核心代码
if(instance==null){
synchronized(Singleton.class){
if(instance == null)
// 核心代码
{
instance=new Singleton();
}
}
}
return instance;
}
}
public class SingletonTest{
public static void main(String[] args){
Singleton s1=Singleton.getInstance();
Singleton s2=Singleton.getInstance();
System.out.println(s1==s2);
}
}
本文详细介绍了JAVA中的多线程概念,包括线程的创建、线程优先级、线程生命周期、线程同步以及死锁问题。通过实例解析了继承Thread类和实现Runnable接口的两种线程创建方式,并探讨了线程同步中的Synchronized关键字应用和单例设计模式的线程安全实现。
708

被折叠的 条评论
为什么被折叠?



