Java面试之线程(1)

问题:
开始三个线程a,b,c,现在bc需要获取a的数据
思路:
如果需要bc需要得到a的数据,首先需要a本身有数据,所以必须a进程先运行,然后运行bc。需使用Semaphore

Semaphore介绍

Semaphore [ˈseməfɔ:®] ,计数信号量,用于限制可以访问资源的线程数量,可以使用这个类来限制线程的访问。
构造方法如下:

Semaphore(int permits)
创建一个 Semaphore与给定数量的许可证和非公平公平设置。
Semaphore(int permits, boolean fair)
创建一个 Semaphore与给定数量的许可证和给定的公平设置。

其中许可证的意思由线程获取,线程获取到许可证后方可运行;公平设置指调用acquire方法的顺序就是获取许可证的顺序,而非公平设置是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证。
主要调用方法如下:

acquire()
从该信号量获取许可证,阻止直到可用,
release()
释放许可证,将其返回到信号量。

下面是Semaphore运用的例子
代码引用来自 https://blog.csdn.net/qq_19431333/article/details/70212663

public class Playground {

	static class Track {
		private int num;
		
		public Track(int num) {
			this.num = num;
		}
		
		public String toString() {
            return "Track{" +
                    "num=" + num +
                    '}';
        }
	}
	
	private Track[] tracks = {new Track(1),new Track(2),new Track(3)};
	
	//volatile 属性强制线程访问主存
	private volatile boolean[] used = new boolean[3];
	
	// 第一个参数许可证数量,第二个参数是否是公平模式
	// 公平模式下调用acquire的顺序就是获取许可证的顺序
	// 而非公平模式是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证
	public Semaphore semphore = new Semaphore(3, true);
	
	// 获取跑道
	public Track getTrack() throws InterruptedException {
		semphore.acquire(); // 获取许可证,阻止直到 “所有”可用
		return getNextAvailableTrack();
	}
	
	// 返回一个跑到
	public void releaseTrack(Track track) {
		if(makeAsUsed(track))
			semphore.release();  // 释放许可证,返回给信号量
	}
	
	
	/**
	 * 返回一个跑道
	 * @param track
	 * @return
	 */
	private boolean makeAsUsed(Track track) {
		for (int i = 0; i < used.length; i++) {
			if (tracks[i] == track) { 
				if (used[i]) { 
					used[i] = false; 
					return true; 
				} else {
					return false; 
				} 
			} 
		}
		return false;
	}

	/**
	 *   查找没人使用的跑道
	 * @return
	 */
	private Track getNextAvailableTrack() {
		for(int i=0;i<used.length;i++) {
			if(!used[i]) {
				used[1] = true;
				return tracks[i];
			}
		}
		return null;
	}
	
}

测试类

public class SemaphoreTest {

	static class Student implements Runnable{
		
		private int num;
		private Playground playground;
		public Student(int num, Playground playground) {
			this.num = num;
            this.playground = playground;
		}
		
		@Override
		public void run() {
			try {
				Playground.Track track = playground.getTrack();
				if(track != null) {
					System.out.println("学生" + num + "在" + track.toString() + "上跑步"); 
					TimeUnit.SECONDS.sleep(2);  // TimeUnit指定时间粒度单位上持续时间,sleep表示睡眠操作
					System.out.println("学生" + num + "释放" + track.toString()); //释放跑道 
					playground.releaseTrack(track);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		Executor executor = Executors.newCachedThreadPool(); 
		Playground playground = new Playground(); 
		for (int i = 0; i < 100; i++) { 
			executor.execute(new Student(i+1,playground)); 
		}
	}
	
}

了解完Semaphore后开始使用解决问题

未解决问题前代码

public class ThreadCommunication {
	private static int num;//定义一个变量作为数据
	
	public static void main(String[] args) {
		Thread threadA = new Thread(new Runnable() {
			@Override
			public void run() {
				//模拟耗时操作之后初始化变量 num
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				num = 1;
			}
		});
		
		Thread threadB = new Thread(new Runnable() {
			@Override
			public void run() {
				 System.out.println(Thread.currentThread().getName()+"获取到 num 的值为: "+num);
			}
		});
			
		Thread threadC = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName()+"获取到 num 的值为: "+num);
			}
		});
		
		//同时开启 3 个线程
		threadA.start();
		threadB.start();
		threadC.start();
	}
}

解决后代码:

/**
 * 	定义一个信号量,该类内部维持了多个线程锁,可以阻塞多个线程,释放多个线程,
 *	线程的阻塞和释放是通过 permit 概念来实现的
 *	线程通过 semaphore.acquire()方法获取 permit,如果当前 semaphore 有 permit 则分配给该线程,
 *	如果没有则阻塞该线程直到 semaphore
 *	调用 release()方法释放 permit。
 *	构造函数中参数: permit(允许) 个数
 *
 */
public class ThreadCommunication2 {
	private static int num;//定义一个变量作为数据
	
	// 创建一个 Semaphore与给定数量的许可证和非公平公平设置
	// 这里设置在线程A运行后再给出许可证
	private static Semaphore semaphore = new Semaphore(0);
	
	public static void main(String[] args) {
		Thread threadA = new Thread(new Runnable() {
			@Override
			public void run() {
				//模拟耗时操作之后初始化变量 num
				try {
					Thread.sleep(1000);
					num = 1;
					// 释放给定数量的许可证,将其返回到信号量
					semaphore.release(2);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		
		Thread threadB = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					semaphore.acquire();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"获取到 num 的值为: "+num);
			}
		});
			
		Thread threadC = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					semaphore.acquire();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"获取到 num 的值为: "+num);
			}
		});
		
		//同时开启 3 个线程
		threadA.start();
		threadB.start();
		threadC.start();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值