利用Java在指定的范围内生成指定数量的随机数

本文介绍了一个Java程序,该程序通过多个线程生成指定区间内的随机数,并确保了线程间的正确同步,避免了共享资源的竞争条件。

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

需求:我们需要在三个不同的数字段产生不同数量的随机数。

比如:[0, 10) 6个;[10, 20) 2个;[20, 30) 2个。

以下为测试代码:

package com.homeland.myapp;

import java.util.Random;


public class RandomSequence {

	public static void main(String[] args) {
		RandomGen d1 = new RandomGen(0, 10, 6);
		RandomGen d2 = new RandomGen(10, 20, 2);
		RandomGen d3 = new RandomGen(20, 30, 2);
		Thread t1 = new Thread(d1);
		Thread t2 = new Thread(d2);
		Thread t3 = new Thread(d3);
		t1.start();
		t2.start();
		t3.start();
	}

}

class RandomGen implements Runnable {
	Random r = new Random();
	int start, end, num;
	
	public RandomGen(int end) {
		this.end = end;
	}
	
	public RandomGen(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public RandomGen(int start, int end, int num) {
		this.start = start;
		this.end = end;
		this.num = num;
	}
	
	@Override
	public void run() {
		int c = 0;
		for (int i = 0; c < num; i++) {
			int a = r.nextInt(end);
			if (a >= start) {
				System.out.println("Number " + i + " is: " + a);
				c++;
			}
		}
		System.out.println("-----------------------");
	}
}

以上三个不同的数字段都只包括第一个数字,不包括最后一个。也即,不包含上限。

以下为测试结果:

Number 0 is: 1
Number 1 is: 5
Number 2 is: 0
Number 3 is: 7
Number 4 is: 6
Number 5 is: 8
-----------------------
Number 12 is: 26
Number 13 is: 28
-----------------------
Number 0 is: 10
Number 4 is: 11
-----------------------

考虑到去掉重复的数字,代码作如下修改:

package com.homeland.myapp;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;


public class RandomSequence {

	public static void main(String[] args) {
		RandomGen d1 = new RandomGen(0, 10, 6);
		RandomGen d2 = new RandomGen(10, 20, 2);
		RandomGen d3 = new RandomGen(20, 30, 2);
		Thread t1 = new Thread(d1);
		Thread t2 = new Thread(d2);
		Thread t3 = new Thread(d3);
		t1.start();
		t2.start();
		t3.start();
	}

}

class RandomGen implements Runnable {
	Random r = new Random();
	int start, end, num;
	
	public RandomGen(int end) {
		this.end = end;
	}
	
	public RandomGen(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public RandomGen(int start, int end, int num) {
		this.start = start;
		this.end = end;
		this.num = num;
	}
	
	@Override
	public void run() {
		Set<Integer> s = new HashSet<Integer>();
		for (int i = 0; s.size() < num; i++) {
			int a = r.nextInt(end);
			if (a >= start) {
				s.add(a);
			}
		}
		System.out.println("there are "+ num +" numbers in range: [" + start + ", " + end + "]:\n");
		System.out.println(s.toString());
		System.out.println("-----------------------");
	}
}
其中一组结果如下:

there are 6 numbers in range: [0, 10]:

[0, 2, 5, 6, 8, 9]
-----------------------
there are 2 numbers in range: [20, 30]:

[22, 26]
-----------------------
there are 2 numbers in range: [10, 20]:

[11, 13]
-----------------------

我修改了代码,在某个位置上加入了syncronized关键字,还有用循环来控制线程的产生:

package com.homeland.myapp;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class RandomSequence {

	public static void main(String[] args) {
		
		int a[][] = {
				{0, 10, 6}, {10, 20, 2}, {20, 30, 4}, 
				{30, 40, 3}, {40, 50, 5}, {50, 60, 7}, 
				{60, 70, 8}, {70, 80, 9}, {80, 90, 4}, {90, 100, 7}};
		
		for (int i = 0; i < a.length; i++) {
			RandomGen d = new RandomGen(a[i][0], a[i][1], a[i][2]);
			Thread t = new Thread(d);
			t.start();
		}
	}

}

class RandomGen implements Runnable {
	Random r = new Random();
	int start, end, num;
	Set<Integer> s = new HashSet<Integer>();
	
	public RandomGen(int end) {
		this.end = end;
	}
	
	public RandomGen(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public RandomGen(int start, int end, int num) {
		this.start = start;
		this.end = end;
		this.num = num;
	}
	
	@Override
	public void run() {
		synchronized (s) {
			for (int i = 0; s.size() < num; i++) {
				int a = r.nextInt(end);
				if (a >= start) {
					s.add(a);
				}
			}
			System.out.println("there are "+ num +" numbers in range: [" + start + ", " + end + "]:\n");
			System.out.println(s.toString());
			System.out.println("-----------------------");
		}// sync
	}
}
但是,我得到如下结果:

there are 4 numbers in range: [20, 30]:

there are 3 numbers in range: [30, 40]:

[35, 39, 30]
-----------------------
there are 6 numbers in range: [0, 10]:

[0, 1, 2, 6, 7, 9]
-----------------------
there are 2 numbers in range: [10, 20]:

[16, 12]
-----------------------
there are 7 numbers in range: [50, 60]:

[51, 50, 55, 53, 52, 59, 58]
-----------------------
[21, 20, 24, 26]
-----------------------
there are 9 numbers in range: [70, 80]:

[70, 71, 76, 77, 79, 72, 73, 74, 75]
-----------------------
there are 5 numbers in range: [40, 50]:

[48, 43, 40, 46, 45]
-----------------------
there are 7 numbers in range: [90, 100]:

[98, 99, 96, 93, 95, 94, 90]
-----------------------
there are 8 numbers in range: [60, 70]:

[68, 69, 64, 65, 66, 67, 62, 60]
-----------------------
there are 4 numbers in range: [80, 90]:

[84, 87, 83, 89]
-----------------------
看起来某些部分的输出时交错的。看来我需要另外一种控制机制。

这个控制机制就是:

Thread.sleep(5000);
把这句放到上面代码中的main()方法的循环中去。


上面的Thread.sleep(5000)不是没有问题的。你可以试想一下,如果数字的范围很大呢?

所以,问题的关键是:如何保证线程同步或者说线程对共享资源的互斥访问呢?把代码做如下修改:

package com.homeland.myapp;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class RandomSequence {

	public static void main(String[] args) throws Exception {
		
		int a[][] = {
				{0, 10, 6}, {10, 20, 2}, {20, 30, 4}, 
				{30, 40, 3}, {40, 50, 5}, {50, 60, 7}, 
				{60, 70, 8}, {70, 80, 9}, {80, 90, 4}, {90, 100, 7}};
		
		for (int i = 0; i < a.length; i++) {
			RandomGen d = new RandomGen(a[i][0], a[i][1], a[i][2]);
			Thread t = new Thread(d);
			t.start();
			Thread.sleep(1);
		}
	}

}

class RandomGen implements Runnable {
	Random r = new Random();
	int start, end, num;
	private Set<Integer> s = new HashSet<Integer>();
	private static Object lock = new Object();
	
	public RandomGen(int end) {
		this.end = end;
	}
	
	public RandomGen(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public RandomGen(int start, int end, int num) {
		this.start = start;
		this.end = end;
		this.num = num;
	}
	
	
	@Override
	public void run() {
		synchronized (lock) {
			for (int i = 0; s.size() < num; i++) {
				int a = r.nextInt(end);
				if (a >= start) {
					s.add(a);
				}
			}
			System.out.println("there are "+ num +" numbers in range: [" + start + ", " + end + "]:\n");
			System.out.println(s.toString());
			System.out.println("-----------------------");
		}// sync
	}
}
你木有看错!静态类成员被所有类实例共享。关键的一句:

private static Object lock = new Object();

当然,你也可以这么改:

package com.homeland.myapp;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class RandomSequence {

	public static void main(String[] args) throws Exception {
		
		int a[][] = {
				{0, 10, 6}, {10, 20, 2}, {20, 30, 4}, 
				{30, 40, 3}, {40, 50, 5}, {50, 60, 7}, 
				{60, 70, 8}, {70, 80, 9}, {80, 90, 4}, {90, 100, 7}};
		
		for (int i = 0; i < a.length; i++) {
			RandomGen d = new RandomGen(a[i][0], a[i][1], a[i][2]);
			Thread t = new Thread(d);
			t.start();
			Thread.sleep(1);
		}
	}

}

class RandomGen implements Runnable {
	static final Random r = new Random();
	static int start, end, num;
	private static Set<Integer> s = new HashSet<Integer>();
	
	public RandomGen(int end) {
		this.end = end;
	}
	
	public RandomGen(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public RandomGen(int start, int end, int num) {
		this.start = start;
		this.end = end;
		this.num = num;
	}
	
	private static synchronized void printSequence() {
		for (int i = 0; s.size() < num; i++) {
			int a = r.nextInt(end);
			if (a >= start) {
				s.add(a);
			}
		}
		System.out.println("there are "+ num +" numbers in range: [" + start + ", " + end + "]:\n");
		System.out.println(s.toString());
		System.out.println("-----------------------");
	}
	
	@Override
	public void run() {
		printSequence();
	}
}

需要注意下,后面的静态方法会产生类似这样的结果:

there are 2 numbers in range: [10, 20]:

[18, 3]
-----------------------
there are 4 numbers in range: [20, 30]:

[18, 3, 20, 23]
-----------------------
there are 4 numbers in range: [20, 30]:

[18, 3, 20, 23]
-----------------------
there are 3 numbers in range: [30, 40]:

[18, 3, 20, 23]
-----------------------
there are 5 numbers in range: [40, 50]:

[18, 3, 20, 23, 42]
-----------------------
there are 7 numbers in range: [50, 60]:

[18, 3, 20, 23, 42, 58, 57]
-----------------------
there are 8 numbers in range: [60, 70]:

[18, 3, 65, 20, 23, 42, 58, 57]
-----------------------
there are 9 numbers in range: [70, 80]:

[18, 3, 65, 20, 23, 76, 42, 58, 57]
-----------------------
there are 4 numbers in range: [80, 90]:

[18, 3, 65, 20, 23, 76, 42, 58, 57]
-----------------------
there are 7 numbers in range: [90, 100]:

[18, 3, 65, 20, 23, 76, 42, 58, 57]
-----------------------
所以,你需要这么修改代码:

package com.homeland.myapp;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class RandomSequence {

	public static void main(String[] args) throws Exception {
		
		int a[][] = {
				{0, 10, 6}, {10, 20, 2}, {20, 30, 4}, 
				{30, 40, 3}, {40, 50, 5}, {50, 60, 7}, 
				{60, 70, 8}, {70, 80, 9}, {80, 90, 4}, {90, 100, 7}};
		
		for (int i = 0; i < a.length; i++) {
			RandomGen d = new RandomGen(a[i][0], a[i][1], a[i][2]);
			Thread t = new Thread(d);
			t.start();
			Thread.sleep(1);
		}
	}

}

class RandomGen implements Runnable {
	static final Random r = new Random();
	int start, end, num;
	
	public RandomGen(int end) {
		this.end = end;
	}
	
	public RandomGen(int start, int end) {
		this.start = start;
		this.end = end;
	}
	
	public RandomGen(int start, int end, int num) {
		this.start = start;
		this.end = end;
		this.num = num;
	}
	
	private static synchronized void printSequence(int start, int end, int num) {
		final Set<Integer> s = new HashSet<Integer>();
		for (; s.size() < num;) {
			int a = r.nextInt(end);
			if (a >= start) {
				s.add(a);
			}
		}
		System.out.println("there are "+ num +" numbers in range: [" + start + ", " + end + "]:\n");
		System.out.println(s.toString());
		System.out.println("-----------------------");
	}
	
	@Override
	public void run() {
		printSequence(start, end, num);
	}
}
我得到的结果类似这种:

there are 6 numbers in range: [0, 10]:

[0, 3, 4, 6, 7, 8]
-----------------------
there are 2 numbers in range: [10, 20]:

[17, 13]
-----------------------
there are 4 numbers in range: [20, 30]:

[20, 25, 26, 28]
-----------------------
there are 3 numbers in range: [30, 40]:

[33, 38, 30]
-----------------------
there are 5 numbers in range: [40, 50]:

[43, 40, 46, 47, 45]
-----------------------
there are 7 numbers in range: [50, 60]:

[55, 54, 53, 59, 58, 57, 56]
-----------------------
there are 8 numbers in range: [60, 70]:

[68, 69, 64, 66, 63, 62, 61, 60]
-----------------------
there are 9 numbers in range: [70, 80]:

[70, 71, 76, 77, 78, 79, 72, 73, 74]
-----------------------
there are 4 numbers in range: [80, 90]:

[86, 80, 82, 88]
-----------------------
there are 7 numbers in range: [90, 100]:

[96, 97, 93, 92, 95, 94, 90]
-----------------------

留个小尾巴:用HashSet去重效率如何呢?



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值