第十四章 多线程

本文详细解析多线程的意义与实现方法,包括Java中的多线程创建方式、同步与死锁概念,以及线程运行机制。通过实例代码展示如何在多线程环境下实现资源共享与同步操作。

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

一、多线程意义

多线程也是为了实现多个任务同时运行。是一个进程中的某一个顺序控制流。

多任务系统的实现方式有2种:

一种是将任务下放到程序单位。进程上面;不同程序完成不同任务。

另一种是将任务下放到线程单位,在一个进程中,将不同的任务分离,交给不同行的线程来执行。可以提高程序的运行效率,解决单线程程序的只有一个运行路径的问题。

在同一个任务中,多个线程可以共享该程序的内存空间。CPU在线程间的切换开销比在进程间的切换小得多,提高程序的运行效率和节省内容空间。

二、多线程实现

java中多线程的实现,很方便。有下面2种方式:

只要继承Thread类,重写里面的run方法;或者实现Runnable接口,重写里面的run方法。

这2中里面,最常用的又是Runnable接口,它将可以解决单继承的问题,并能实现线程任务与类的分离。

三、synchronized同步及死锁

1、同步synchronized

在多线程程序中,当多个线程同时操作同一资源时,特别是修改数据时,会造成数据的紊乱。使得程序出现意想不到的情况。

同步就是为了解决数据紊乱的问题,在资源上面加把锁,

(只有取得锁那个线程才能访问同步所在的代码)

使用synchronized可选修饰符实现同步。

分为同步方法和同步块:

public   synchronized   void    method (){

//方法实现代码

}

public   void   method (){

            synchronized(锁定对象//一般为该对象自身){

                         //数据操作代码

           }

           //方法实现

}

即使有A线程正在使用对象的(同步方法a), 线程B也可以访问该对象的(其他非同步方法)。

同一时间,如果有线程C想访问对象的(同步方法b),由于一个对象只有一个锁,C线程将无法访问对象的(同步方法b)。

所以,只有synchronized中的代码才能真正实现同步,对象的其他部分无影响。对于对象的其他非同步方法,任意线程可以随时访问。

2、死锁

只有同步中,才会出现死锁

当有2个线程循环依赖于一对同步对象时,形成一个需求循环,而无法打破时就是死锁了。

 

解决死锁:

线程运行需要访问多个同步资源时:

先获取低优先级的资源,再获取优先级高的资源,如果能够获得,则继续执行。

一旦不能获得高优先级资源的锁时,就放弃已获得的资源的锁,用wait方法

四、线程的运行机制

线程的生命周期为,new产生之后到 run方法结束。

1),普通线程(无同步)

线程产生之后调用start方法启动run方法后,线程就进入runnable状态(就绪状态)

在runnable状态(就绪状态)等待JVM分配资源,占用虚拟cpu时,开始运行running(运行状态)

在running(运行状态)如果线程调用sleep方法,或者join方法时,线程就进入到了blocked(阻塞状态)

在blocked(阻塞状态)如果线程一段时间后,可以恢复到runnable状态(就绪状态)循环直到running(运行状态)将run方法执行完成。死亡。

2),同步线程(同步资源)

如果线程有访问同步资源时,线程会多出下面的状态。

 

在running(运行状态),如果需要用到同步对象。那么就会进入到该对象的锁池当中,等待获取锁。

一旦得到锁(只会有个线程获得),那么线程就会进入runnable状态(就绪状态)

 

在running(运行状态)如果线程自己调用wait方法时,会放弃已获得的同步对象的锁,线程进入wait等待池,同时JVM通知这个对象的锁池当中的某个线程,将锁给它,这个线程就可以进入runnable状态(就绪状态)

 

对于在某个对象的wait等待池中的线程,使用这个对象的线程调用notify方法时,就会唤醒对象等待wait池中的某个线程;

使用这个对象的线程调用notifyAll方法时,就会唤醒对象等待wait池中的所有线程。被唤醒的线程就会进入该对象的锁池,继续等待 锁。

 

1、sleep

方法不会使得线程丢失当前对象锁,相当于是自我休眠

2、wait

线程会失去对象锁。自我放弃

3、join

使用于业务或者操作(任务)的依赖时。

(1)、使得当前进行的任务暂停,
(2)、运行join调用者的线程,直到调用者结束或者等待指定的时间。
(3)、最后继续运行被暂停的任务线程

 

列子:

import java.util.ArrayList;


public class TestThread {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
//		Test test = new Test();
//		new MyThread(test,"boy").start();
//		new MyThread(test,"girl").start();
//		new MyThread(test,"rabbit").start();
		
		
//		//测试哲学家问题代码
		
//		ArrayList<KuaiZi> kuaiZi = new ArrayList<KuaiZi>();
//		for(int i = 0 ; i < 5 ; i ++){
//			kuaiZi.add(new KuaiZi("筷子"+i));
//		}
//		for(int i = 0 ; i < 5 ; i ++){
//			new Peple(i,"哲学家"+i,kuaiZi).start();
//		}
		
		
//		//测试,同一对象,2个线程使用它,其中一个调用同步方法,另一个调用
//		//非同步方法,是否能同时访问?
		//结果:多个线程可以访问对象的非同步方法。同步方法不锁定对象。
		//     同步块锁定对象也可以访问,同步块也无效
		KuaiZi kz1 = new KuaiZi("铁的");
		KuaiZi kz2 = new KuaiZi("银的");
//		new MyThread1(kz1).start();
		new MyThread2(kz1,kz2).start();
//		
	}

}

public class MyThread1 implements Runnable {
	private KuaiZi kz;
	

	public MyThread1(KuaiZi kz) {
		super();
		this.kz = kz;
	}

	public void start(){
		new Thread(this).start();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			try {
//				this.kz.setGetAble(false);
				System.out.println(Thread.currentThread().getName()+"开始");
				System.out.println("非同步访问名字:"+this.kz.getName());
//				this.kz.setGetAble(true);
				Thread.sleep(500);
//				this.kz.setGetAble(true);
				System.out.println(Thread.currentThread().getName()+"结束\n");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

}

public class MyThread2 implements Runnable {
	private KuaiZi kz1;
	private KuaiZi kz2;
	
	public MyThread2(KuaiZi kz1, KuaiZi kz2) {
		super();
		this.kz1 = kz1;
		this.kz2 = kz2;
	}
	
	
	public void start(){
		new Thread(this).start();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
			System.out.println(Thread.currentThread().getName()+"***************************      同步方法开始");
			{
				this.kz1.setGetAble(false);
				this.kz2.getName();
				System.out.println("!!!!!!!!!!!!!!!!!!!!!!");
//				if(Thread.currentThread().holdsLock(kz1) ){
//					System.out.println("11111111111111");
//				}else{
//					System.out.println("00000000000000000");
//				}
//				if(Thread.currentThread().holdsLock(kz2)){
//					System.out.println("22222222222222222");
//				}else{
//					System.out.println("00000000000000000");
//				}
//				if(Thread.currentThread().holdsLock(kz2) && Thread.currentThread().holdsLock(kz1) ){
//					System.out.println("333333333333333");
//				}else{
//					System.out.println("00000000000000000");
//				}
				
			}
			
			
			
			System.out.println(Thread.currentThread().getName()+"***************************      同步方法结束\n");
		}
	}

}


 

public class KuaiZi {
	private boolean getAble;
	private String name;
	
	public KuaiZi(String name) {
		super();
		this.name = name;
		this.getAble = true;
	}

	public KuaiZi(){
		
	}

	public String getName() {
//		if(Thread.currentThread().holdsLock(this)){
//			System.out.println(Thread.currentThread().getName()+"------------------------------------------持有锁:"+this.name);
//		}else{
//			System.out.println(Thread.currentThread().getName()+"*************没有锁:"+this.name);
//		}
		synchronized(this){
			return name;
		}
	}

	public  int setGetAble(boolean getAble) {
		synchronized(this){
			this.getAble = getAble;
			if(this.getAble){
				System.out.println("同步方法      "+this.name+"被释放了*********");
			}else{
				System.out.println("同步方法                      "+this.name+"被锁定了!!!!!!!!!!!");
			}
			
			//测试同步锁代码,平时注释掉
//			while(true)
//			{
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				if(Thread.currentThread().holdsLock(this)){
					System.out.println(Thread.currentThread().getName()+"------------------------------------------持有锁:"+this.name);
				}else{
					System.out.println(Thread.currentThread().getName()+"------------------------------------------丢失锁:"+this.name);
				}
				this.getName();
//			}
		}
		return 1;
	}

	public boolean isGetAble() {
		return getAble;
	}	
}
import java.util.ArrayList;


public class Peple implements Runnable {
	private int position;
	private String name;
	private ArrayList<KuaiZi> al;
	
	public Peple(int position, String name, ArrayList al) {
		super();
		this.position = position;
		this.name = name;
		this.al = al;
	}

	public Peple(){
		
	}
	
	public Peple(int position, String name) {
		super();
		this.position = position;
		this.name = name;
	}
	public void start(){
		new Thread(this,this.name).start();
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(true){
				this.take();
				this.reset();
		}
	}
	
	public void take(){
//		synchronized(this.al.get(this.position)){
		if(this.al.get(this.position).isGetAble()){
			//先锁定筷子,再使用
			this.al.get(this.position).setGetAble(false);
			System.out.println(this.name+"得到了:"+this.al.get(this.position).getName()+"!!!!");
			
			if(!this.al.get((this.position+1)%5).isGetAble()){
//				try {
//				//如果下一根筷子无法得到,就放弃现在拿到的筷子   的锁
//					wait();
//				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					System.out.println(this.name+"获取   :"+this.al.get((this.position+1)%5).getName()+"失败!等待唤醒…………");
//				}
			}//如果拿到了,则继续使用,并吃饭
			else{
//				synchronized(this.al.get((this.position+1)%5)){
					//先锁定筷子,再使用
					this.al.get((this.position+1)%5).setGetAble(false);
					System.out.println(this.name+"得到了:"+this.al.get((this.position+1)%5).getName()+"!!!!");
					this.eat();
					//吃完就释放二根筷子
					this.al.get((this.position+1)%5).setGetAble(true);
					
					//通知第二根根筷子等待的线程
//					notifyAll();
//				}
			}
			//通知第一根筷子等待的线程
			this.al.get(this.position).setGetAble(true);
//			notifyAll();
		}
		else{
			
			System.out.println(this.name+"获取   :"+this.al.get(this.position).getName()+"失败!等待唤醒…………");
		}
	}
	
	public void eat(){
		System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!----------------------"+this.name+":正在吃饭***");
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("----------------------------------"+this.name+":吃完了");
	}
	
	public void reset(){
		System.out.println(this.name+":正在休息…………");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(this.name+":休息完了…………");
		
	}

	public String getName() {
		return name;
	}
	
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值