Java 线程

多线程

并发与并行

并发:两个或多个事件在同一个时间段内发生
并行:两个或多个事件在同一个时刻发生(同时)

线程与进程

进程:指一个内存中运行的应用程序(进入到内存中)
线程:是进程中的一个执行单元
多线程好处:效率高 各个单元互不影响

线程调度

分时调度:所有线程轮流使用CPU,平均分配每个线程占用CPU的时间
抢占式调度:优先让优先级高的线程使用CPU,如果优先级相同,随机选择一个,Java使用的是抢占式调度

主线程

执行主(main)方法的线程
单线程程序:只有一个线程,从main方法开始,从上往下执行

JVM执行main方法,main方法进入栈内存
JVM会找操作系统开辟一条main方法路径通向CPU(叫做主线程)
CPU通过这个路径执行main方法

Thread 类

创建Thread类的子类

在子类中重写Thread类中run方法,设置线程任务
创建子类对象
调用start方法,开启线程,执行run方法
void start() 使该线程开始执行 Java虚拟机调用run方法
结果 main线程与该run线程并发运行
且多次启动一个线程是非法的。特别是线程结束后不能重新启动

public class Thread1 extends Thread{
	@Override
	void run(){
		//覆写run的内容
	}
	public static void main(String []args){
		Thread1 mt = new Thread1();
		mt.start(); // mt的run加线程入
		//main 线程内容
	}
}

获取线程名称

Thread 中的 String getName(); 返回该线程的名称
static Thread currentThread(); 返回当前正在执行的线程对象的引用

public class MyThread extends Thread{
	public MyThread(){}
	public MyThread(String name){
		super(name);
	}
	public static void main(String []args){
		MyThread mt = new MyThread();
		mt.setName("new name");
		mt.start();
		MyThread("another name").start();
	}
	@Override
	public void run(){
		String name = getName();
		System.out.println("name");
		Thread t = Thread.currentThread();
		name = t.getName();
		System.out.println("name");
	}
}

线程暂停

public static void sleep(long millis) //使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)

Runnable接口

该接口只含一个run方法
创建一个Runnable接口的实现类
实现类必须定义一个称为run的无参数方法
创建一个实现类对象
创建Thread类对象,传递实现类对象
调用start() 启动线程

public class MyThread implements Runnable{
	public static void main(String []args){
		MyThread mt = new MyThread();
		Thread t = new Thread(mt);
		t.start();
	}
	@Override
	public void run(){
		// run的重写方法
	}
}

避免了单继承的局限性(一个类只能继承一个类)
增强了程序的扩展性 降低了程序的耦合性
实现Runnable接口的方式 把设置线程任务和管理线程分开

匿名内部类方式实现线程的创建

匿名内部类产物:子类/实现类对象

new 父类/接口(){
	//重复父类/接口的方法
}
public class MyThread extends Thread{
	public static void main(String []args){
		new Thread(){
			public void run(){
				//覆写内容
			}
		}.start();
		//
		Runnable r = new Runnable(){
			public void run(){
				//覆写内容
			}
		}
		new Thread(r).start();
		//或者
		new Thread(new Runnable(){
			public void run(){
				//覆写内容
			}
		}).start();
	}
}

线程安全与线程同步

同步代码块

同步中的线程 没有执行完不会归还锁对象

synchronized(锁对象){
	//访问共享数据的代码
	//保证多个线程使用的锁对象是同一个
	//把同步代码块锁住 只让一个线程在同步代码块中执行
}
public class RunnabkeImpl implements Runnable{
	private int ticket=100;
	Object obj = new Object();
	@Override
	public void run(){
		while(true){
			synchronized(obj){
				if(ticket>0){
					System.out.println("ticket");
					ticket--;
				}
			}
		}
	}
}

同步方法

修饰符 synchronized 返回值类型 方法名(参数列表){
	//方法内容
}
public class RunnabkeImpl implements Runnable{
	private int ticket=100;
	Object obj = new Object();
	@Override
	public synchronized void run(){
		while(true){
			if(ticket>0){
				System.out.println("ticket");
				ticket--;
			}
		}
	}
}

静态的同步方法 锁对象是本类的class属性–>class 文件对象(反射)

Lock锁

lock接口中的方法

void lock()
void unlock()

在成员位置创建一个ReentrantLock对象
在可能会出现安全问题的代码前调用lock方法获取锁
执行代码后 调用unlock 解锁

public class RunnabkeImpl implements Runnable{
	private int ticket=100;
	Object obj = new Object();
	Lock lock = new ReentrantLock();
	@Override
	public void run(){
		while(true){
		lock.lock();// 加锁
			if(ticket>0){
				System.out.println("ticket");
				ticket--;
			}
		lock.unlock();//解锁
		}
	}
}

线程状态

线程状态转换图

在这里插入图片描述

线程等待

  • Timed Waiting 计时等待

     限时暂停一个线程
     如使用sleep() 语句
     进入到一个计时等待的状态
     注意:
     	进入TIMED_WAITING 状态 一般调用sleep方法。单线程也可以调用
     	为了让其他线程有机会执行,将Thread.sleep() 的调用放线程run() 之内
     	sleep() 与 锁 无关,线程睡眠到期自动苏醒 并返回刀Runnable状态
     	sleep() 指定的时间是线程不会运行的最短时间,睡眠结束后线程不一定马上开始
    
  • block 锁阻塞状态

  •  一个正在阻塞等待一个监视器锁(锁对象)的线程处于的状态
     如线程A与线程B使用同一锁,如果线程A获取到锁,线程A进入Runnable状态
     而线程B进入Blocked锁阻塞状态
    
  • waiting 无限等待

     一个正在无限期等待另一个线程执行一个特别的(唤醒)动作的线程处于这一状态
     这其实并不是一个线程操作,而是多个线程间的通信
     多个线程会争取锁,同时相互之间又存在协作关系
     像争夺唯一一台电脑时,第一个大佬把题AC了(调用wait() 进入Waiting状态)
     放出电脑(失去同步锁)
     此时notify() 另外两个大佬
     告诉他俩可以抢电脑(同步锁)AC题(run),然后其中一个大佬就抢到了(进入Runnable)
     另一个大佬想出题却没有抢到电脑(锁对象) 就只能自闭(Blocked)等到上面大佬写完(释放锁对象)
    

在这里插入图片描述
wait方法可以带参数,差不多相当于sleep的作用(计时等待)在等待中可以notify退出休眠
不带参数就只能等notify(无限等待)

等待与唤醒机制(线程间通信)

多个线程的竞争机制

wait()
//线程不再活动,不再参与调度,进入wait set 
//不会浪费CPU资源 也不会竞争锁
//等到别的线程执行notify时才能从wait set中释放
notify()
//选取所通知对象的wait set中的一个线程释放
notifyall()
//释放所通知对象的wait set 上的全部线程

调用wait与notify的细节

  1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
  2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
  3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法
    下面搞一段从网上弄来的代码
    包子类
public class BaoZi { 
String pier ; 
String xianer ; 
boolean flag = false ;//包子资源 是否存在 包子资源状态 
}

食客类

public class ChiHuo extends Thread {
    private BaoZi bz;

    public ChiHuo(String name, BaoZi bz) {
        super(name);
        this.bz = bz;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bz) {
                if (bz.flag == false) {//没包子 
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("吃货正在吃" + bz.pier + bz.xianer + "包子");
                bz.flag = false;
                bz.notify();
            }
        }
    }
}

包子铺

public class BaoZiPu extends Thread {
    private BaoZi bz;

    public BaoZiPu(String name, BaoZi bz) {
        super(name);
        this.bz = bz;
    }

    @Override
    public void run() {
        int count = 0; //造包子
        while (true) { //同步
            synchronized (bz) {
                if (bz.flag == true) {//包子资源 存在 
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }// 没有包子 造包子 
                System.out.println("包子铺开始做包子");
                if (count % 2 == 0) {
                    bz.pier = "冰皮";
                    bz.xianer = "五仁";
                } else {
                    bz.pier = "薄皮";
                    bz.xianer = "牛肉大葱";
                }
                count++;
                bz.flag = true;
                System.out.println("包子造好了:" + bz.pier + bz.xianer);
                System.out.println("吃货来吃吧"); //唤醒等待线程 (吃货)
                bz.notify();
            }
        }
    }
}

测试类

public class Demo {
    public static void main(String[] args) { //等待唤醒案例 
        BaoZi bz = new BaoZi();
        ChiHuo ch = new ChiHuo("吃货", bz);
        BaoZiPu bzp = new BaoZiPu("包子铺", bz);
        ch.start();
        bzp.start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值