JAVA初学笔记&宋红康JAVA高级篇(其十二)

本文详细介绍了JAVA中的多线程概念,包括线程的创建、线程优先级、线程生命周期、线程同步以及死锁问题。通过实例解析了继承Thread类和实现Runnable接口的两种线程创建方式,并探讨了线程同步中的Synchronized关键字应用和单例设计模式的线程安全实现。

多线程与多进程

多线程的创建

常用方法
  • 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类
  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run()
  3. 创建Thread类的子类的对象
  4. 通过此对象调用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接口
  1. 定义子类,实现Runnable接口。
  2. 子类中重写Runnable接口中的run方法。
  3. 通过Thread类含参构造器创建线程对象。
  4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
  5. 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
区别
继承Thread实现Runnable
线程代码存放Thread子类run方法中线程代码存在接口的子类的run方法
实现方式的好处
  • 避免了单继承的局限性
  • 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线 程来处理同一份资源。

线程优先级

调度策略
  • 时间片:“拉链图式”
  • 抢占式:优先级高的线程,优先获得cpu的控制权
Java的调度方法
  • 同优先级默认组成队列,使用时间片策略
  • 对高优先级,优先使用抢占式
优先级等级
MAX_PRIORITY:10 

MIN _PRIORITY:1 

NORM_PRIORITY:5 
涉及的方法
  • getPriority():返回线程优先值
  • setPriority(int newPriority):改变线程的优先级
补充
  1. 线程创建时继承父线程的优先级

  2. 低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用

  3. 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);
    } 
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值