被synchronized修饰的方法在某一时刻只允许一个线程访问,访问该方法的其它线程都会发生阻塞,直到当前线程访问完毕后,其它线程才有机会执行方法。
另外
public final string getname():获取线程的名称。
public static thread currentthread():返回当前正在执行的线程对象,这样就可以获取任意方法所在的线程名称。
thread.currentthread().getname()
现将上面的单线程改成多线程实现
本篇文章多线程的创建以及实现用runnable接口实现 (1)
import java.util.scanner;
import com.sun.deploy.security.selectablesecuritymanager;
import java.util.random;
public class 微信发红包多线程 {
public static void main(string[] args) {
scanner scanner=new scanner(system.in);
int n;
double money;
system.out.println("请输入您想要发的红包数量");
n=scanner.nextint();
system.out.println("请输入您发送的红包金额");
money=scanner.nextdouble();
t3 t3=new t3(n,money);//创建runnable实现类的实例
for (int j = 1; j <= n; j++) {
new thread(t3, "红包获得者" + j).start();//以上面创建的实例作为thread的参数来创建thread对象,并为thread对象指定一个名字,用线程对象的start方法来启动该线程。
}
}
}
class t3 implements runnable {//实现runnable接口
public double remain;//有红包被领取后的余额
int n;//红包数量
public synchronized void run() {//同步方法,在某一时刻只允许一个线程访问,防止数据错乱
rob();
}
t3(int n, double money) {
this.remain = money;
this.n = n;
}
int a = n;
public void rob() {
double x2;
if (n != 1) {//因为最后一个人领取金额为前面人领取红包后剩下的,所以无需再进行随机
x2 = process();//取随机金额
while (judge(x2) != 1) {//判断取到的随机金额是否非法,即是否能保证后来每个红包领取者领到最低金额0.01
x2 = process();//若非法则重新取随机金额
}
remain = remain - x2;//当领取成功后余额减去领走的金额
n--; //确保每次判断人数为红包数减一
} else {
x2 = remain;//因为最后一个人领取金额为前面人领取红包后剩下的,所以无需再进行随机
string str = string.valueof(x2);
string str1 = string.format("%.2f", x2);
x2 = double.parsedouble(str1);
}
thread th = thread.currentthread();//返回当前正在执行的线程对象
string th_name = th.getname();//获取线程的名称
system.out.println(th_name + "抢到" + x2 + "元");
}
public int judge(double x) {//判断函数
if (remain - x > (n - 1) * 0.01) {//确保后来红包领取者能领到最低金额0.01
return 1;
} else return 0;
}
public double process() {//实现红包金额随机的函数
double x2;
double x1;
string str1;
random random = new random();//随机数为取0到1之间的任意double值
x1 = remain * random.nextdouble();
str1 = string.format("%.2f", x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位
x2 = double.parsedouble(str1);//再将字符串型数据转换成double型
while (x2 == 0) {//如果所取金额非法则回炉重造
x1 = remain * random.nextdouble();
str1 = string.format("%.2f", x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位
x2 = double.parsedouble(str1);//再将字符串型数据转换成double型
}
return x2;
}
}
程序运行结果如下:
(2)
import java.util.random;
import java.util.scanner;
public class 简易微信发红包多线程2 {
public static void main(string[] args) {
scanner scanner=new scanner(system.in);
double money=0;//红包总金额
int n;//红包个数
system.out.println("请输入您想要发的红包数量");
n=scanner.nextint();
system.out.println("请输入您发送的红包金额");
money=scanner.nextdouble();
if(money/n==0.01){//当所发金额刚好为每人0.01元时
t4 t4=new t4(money,n);
for(int i=1;i<=n;i++) {
new thread(t4,"红包获得者"+i).start();
}
}else{
t1 t1=new t1(money,n);
for(int i=1;i<=n;i++) {
new thread(t1,"红包获得者"+i).start();
}
}
}
}
class t1 implements runnable{
double remain;
int n;
t1(double money,int n){
this.remain=money;
this.n=n;
}
@override
public synchronized void run() {
rob();
}
public void rob(){
double max;//最大可领红包金额
double x1;//随机金额
double x2;//所得金额
if(n!=1) {//前n-1个红包领取者领的红包为随机金额红包
max=remain-(n-1)*0.01;//最大可领红包金额为剩下的人都获得最小金额0.01
random random=new random();
x1=(double)random.nextint((int) ((max-0.01)*100));
//用nextint而不用nextdouble的原因是nextdouble无法设置seed
//上式中max-0.01,下面的x2+0.01即解决了随机数取0导致红包获得者没抢到钱的问题
x1/=100.0;
x2=x1+0.01;
remain=remain-x2;
n=n-1;
thread th=thread.currentthread();//获取当前线程
string th_name=th.getname();//获取线程名字
system.out.println(th_name+"获取金额为:"+string.format("%.2f", x2)+"元");
}
else {//最后一人领的红包为前n-1个人领完后剩下的红包
thread th=thread.currentthread();//获取当前线程
string th_name=th.getname();//获取线程名字
system.out.println(th_name+"获取金额为:"+string.format("%.2f", remain)+"元");
}
}
}
class t4 implements runnable{
double remain;
int n;
t4(double money,int n){
this.remain=money;
this.n=n;
}
public synchronized void run() {
rob();
}
public void rob(){
thread th=thread.currentthread();//获取当前线程
string th_name=th.getname();//获取线程名字
system.out.println(th_name+"获取金额为:"+string.format("%.2f", remain/n)+"元");
}
}
程序运行结果如下:
(3)
import java.util.random;
import java.util.scanner;
public class 简易微信发红包多线程3 {
public static void main(string[] args) {
int p,n;
double money;
system.out.println("请输入您发送的红包金额");
scanner scanner=new scanner(system.in);
money=scanner.nextdouble();
system.out.println("请输入您发送的红包数量");
n=scanner.nextint();
system.out.println("请输入参与抢红包的人数");
p=scanner.nextint();
hh hh=new hh(money,n);
for (int i=1;i<=p;i++){
new thread(hh,"第"+i+"个人").start();
}
}
}
class hh implements runnable{
double money;
int n;
int count =0;//计数器
double remain;
hh(double money,int n){
this.money=money;//总金额
this.n=n;//红包数
this.remain=money;//所剩金额
}
@override
public synchronized void run() {
rob();
}
public void rob(){
double x1,x2,d;
string s1,s2;
thread th=thread.currentthread();//获取当前线程
string th_name=th.getname();//获取线程名字
random random=new random();
d=money/(n-1);//设置范围让每次所得金额不超过总数的1/(n-1),这样也就避免了一次取得过大导致后面抢的红包不能保证每个最少0.01
x1=d*random.nextdouble();
s1=string.format("%.2f",x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位
x1 = double.parsedouble(s1);//再将字符串型数据转换成double型
while(x1==0||x1==money/(n-1)){
x1=d*random.nextdouble();
s1=string.format("%.2f",x1);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位
x1 = double.parsedouble(s1);//再将字符串型数据转换成double型
}
s2= string.format("%.2f",remain);//转化成字符串型用字符串型的format进行格式化处理,红包金额最多取到小数点后两位
remain = double.parsedouble(s2);//再将字符串型数据转换成double型
if (count<n-1){//前n-1个红包金额为随机金额
system.out.println(th_name+"抢到了"+s1+"元");
remain-=x1;
count++;
}else if (count==n-1){//第n个为前n-1个红包抢完所剩金额
system.out.println(th_name+"抢到了"+s2+"元");
count++;
}else if (count>n-1){//红包被抢完后再来的
system.out.println(th_name+"哎呀,手慢了!没抢到!");
count++;
}
}
}