线程

本文详细介绍了Java线程的创建、启动、状态转换及线程调度机制,探讨了线程同步、互斥与协作的基本原理及实现方法,包括Synchronized关键字的使用、死锁预防、wait-notify机制的应用,以及如何在多线程环境下共享资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程的创建方式

  1. 声明一个Thread类的子类,并覆盖run()方法,并创建该类对象
    Class MyThread extends Thread(){
    public void run(){
    //覆盖该方法
    }
    }
    Thread thread = new MyThread ();
  2. 以Runnable接口实现类对象为构造参数创建Thread类对象
    Class MyRunnable implements Runnable(){
    public void run(){
    //实现该方法
    }
    }
    Thread thread = new Thread(new MyRunnable());

线程的启动

注:要启动一个线程,必须调用线程的线程的start()。
调用start()方法时,该线程启动,并被放入线程调度队列中。JVM负责调度该线程,并调用该线程的run()方法。
run()方法是具体实现线程的功能,不能通过run()方法来启动线程。

线程的状态

  1. 新建(new):
    线程被创建,但start方法没有调用,处于新建状态
  2. 就绪/可运行(RUNNABLE):
    线程的start方法已经被调用,正在等待CPU的使用权,此时即为就绪状态
  3. 运行(RUNNING):
    线程占用CPU,执行程序代码,此时线程即为运行状态
  4. 阻塞(BLOCKED/ WAITING/ / TIMED_WAITING):
    线程对象放弃CPU,暂时停止运行,不会在竞争占用CPU,此时线程即处于阻塞状态。
    表现形式:
    睡眠(Sleeping):线程通过执行sleep()方法暂时终止;
    等待(WAITING/ / TIMED_WAITING):如果调用wait(),join()方法,线程将处于等待状态,用于协调两个或者多个线程并发运行
    等待I/O操作等等…
    处于阻塞状态下的线程对象不会竞争和占用CPU,
    结束阻塞状态,线程进入就绪状态,而非运行状态
  5. 死亡( D TERMINATED):
    线程对象的run()方法执行完毕(或者是stop方法被调用之后),线程就处于死亡状态

部分方法

  1. sleep():使当前线程睡眠,从运行进入阻塞状态
  2. 调用其他线程的join方法,使当前线程等待其他线程运行完毕
  3. 线程由于等待一个I/O事件被阻塞
  4. 对象的wait()方法,使当前线程等待(需和同步机制配合使用)
  5. 对象的yield()方法,使当前线程显示让出CPU控制权(让步)。从运行状态进入就绪状态

线程调度

概念:合理分配多个线程对CPU资源的占用,即线程调度
线程调度的原因:多线程对CPU大量需求与CPU的数量不足之间的矛盾
线程调度的策略:
1. 任何线程都有占用CPU的机会
2. 防止线程长期占用CPU不放弃,即应该控制线程适当放弃对CPU的占用
3. 符合其他策略目标
线程调度的实现手段:
合理设定优先级
使用Thread.yield()、Thread.sleep()、join()等方法

守护线程

其他非守护线程运行结束后会自动结束的线程
相关方法:
	final void setDaemon(boolean on):将线程标记为守护线程
	final boolean isDaemon();检查线程是否是守护线程

多线程

线程同步

基本概念:
	线程同步是指在访问共享资源时,多个线程相互之间的协调和控制
	线程同步的目的:实现多线程对共享资源有序可控访问,保障共享资源数据安全,避免死锁使整个系统正常运行
	实现线程同步的方式是:互斥和协作
注:
	并行程序设计中,共享资源越多,程序设计将越复杂,所以应该尽量减少共享资源的使用

线程的互斥同步

当有多个并行线程执行时,由于线程占用和放弃CPU在微观上无法预知,所以对于共享数据的插入、删除、更新等操作,若不采取一定措施,所取得数据很有可能不正确。
为了避免上述状况,java提供了一种同步机制的办法,即互斥。使用Synchronized关键字即加锁的方式来实现。
互斥:指临界资源同时只允许一个线程对其进行访问,具有唯一性和排他性。保证了线程对临界资源访问的原子性。
Synchronized关键字:保证同时只有一个线程执行特定的代码块,即实现该代码块的原子性。
	三种方式:
		同步代码块、同步实例方法、同步类方法
同步代码块:
synchronized (obj){
	//...
}
obj是一个对象,可以称为该代码块的锁对象
同步实例方法:
public synchronized void show(){//功能代码}
同步静态方法:
public static synchronized void show(){//功能代码}
死锁
当两个线程循环依赖于一对同步对象时,发生死锁。	
	Eg:一个线程进入对象obj1的监视器,并且等待对象obj2的监视器。但另一个线程进入obj2监视器,并且等待对象obj1监视器。
死锁很少发生,一旦发生就很难调试。
线程协作
线程协作是多线程同步互斥的基础上,使线程之间依照一定条件,有目的、有计划的交互协同工作。这是一种比较高级的线程同步方式。
Java提供了一个精心设计的线程间通信机制,即wait-notify机制,通过该机制可以实现线程协作。
wait-notify机制是通过使用wait(),notify()和notifyAll()三个方法来实现的。(这三个方法都是Object类中,final修饰的实例方法。这三个方法必须在synchronized代码中应用,而且只有锁对象才可以调用。即持有锁对象监听器的线程才可以调用锁对象的这三个方法)
wait():调用该方法的线程退出监听器并进入等待状态,直到其他线程进入相同的监听器并调用notify()方法;
notify():通知等待(该方法所属对象)监听器的(多个)线程中的一个结束等待
notifyAll():通知等待(该方法所属对象)监听器的所有结束等待(即唤醒所有等待当前线程所持有的监听器的线程)

线程协作实例:

//橱柜
public class Cupboard{
	private int count;
	private int size;
	public Cupboard(int size){
		this.size = size;
	}
	public void add (){
		count++;
		syso(Thread,currentThread().getName()+":放入一个面包,橱柜内的面包数为"+count);
	}
	public void remove(){
		count--;
		syso(Thread,currentThread().getName()+":取出一个面包,橱柜内的面包数为"+count)
	}
	public boolean isEmpty(){
		return count<1;
	}
	public boolean isFull(){
		return count>=size;
	}
}
//面包师
public class Baker extends Thread(){
	private Cupborad cupborad;
	public Baker(Cupborad cupborad){
		this.cupborad = cupborad;
		this.setName("面包师");
	}
	public void run(){
		try{
			for(int i = 0;i<100;i++){
				synchronized(cupborad){
					while(cupborad.isFull()){
						syso(this.getName+"橱柜满,等待")
						cupborad.wait();
					}
					cupborad.add();
					cupborad.notifyAll();
					Thread.sleep(1000);
				}
			}catch(e){
				
			}
		}
	}
}
//伙计
public class Salesman extends Thread{
	private Cupborad cupborad;
	public Salesman(Cupborad cupborad){
		this.cupborad = cupborad;
		this.setName("伙计");
	}
	public void run(){
		try{
			for(int i = 0;i<100;i++){
				synchronized(cupborad){
					while(cupborad.isFull()){
						syso(this.getName+"橱柜空,等待")
						cupborad.wait();
					}
					cupborad.remove();
					cupborad.notifyAll();
					Thread.sleep(1000);
				}
			}catch(e){
				
			}
		}
	}
}
//测试
public class store{
	public static void main(String[] args){
		Cupborad cupborad = new Cupborad(5);
		Baker baker = new Baker(cupborad);
		Salesman salesman = new Salesman(cupborad);
		baker.start();
		salesman.start();
	}
}

同一进程中线程共享的资源

1. 堆	(由于堆是在进程空间中开辟出来的,因此new出来的都是共享的)
2. 全局变量		(与某一函数是无关的,因此也与某一线程无关)
3. 静态变量			(从属于类)
4. 文件等公共资源

多线程使用共享资源

  1. 方法一:
public class A {
	
	private int i;
	public A(int i) {
		this.i = i;
	}
	public synchronized void add() {
		++i;
		System.out.println(Thread.currentThread().getName()+"********"+i);
	}
	
	public synchronized void del() {
		--i;
		System.out.println(Thread.currentThread().getName()+"********"+i);
	}
	public synchronized int getI() {
		return this.i;
	}
}

public class TestThread {
	public static void main(String[] args) {
		A a = new A(10);
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				a.add();
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				a.del();
			}
		}).start();
		System.out.println(a.getI());
	}
}
  1. 方法二:
public class A {
	
	private int i;
	public A(int i) {
		this.i = i;
	}
	public synchronized void add() {
		++i;
		System.out.println(Thread.currentThread().getName()+"********"+i);
	}
	
	public synchronized void del() {
		--i;
		System.out.println(Thread.currentThread().getName()+"********"+i);
	}
	public synchronized int getI() {
		return this.i;
	}
}

public class Th implements Runnable{

	private final A a;
	
	public Th(A a) {
		this.a = a;
	}
	
	@Override
	public void run() {
		a.add();
	}
}

public class Th2 implements Runnable{
	
	private final A a;
	
	public Th2(A a) {
		this.a = a;
	}
	
	@Override
	public void run() {
		a.del();
	}
}
public class Test {
	public static void main(String[] args) {
		A a = new A(0);
		
		Thread del = new Thread(new Th2(a));
		del.start();
		Thread add = new Thread(new Th(a));
		add.start();	
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值