Java车票,车站,生命周期,龟兔赛跑,同步锁,礼让,守护线程,挖金矿【诗书画唱】
个人理解:加同步锁等的时候,就可以让线程”按顺序排队“,一个一个地抢CPU,一个抢完对应的每次有的CPU了,另一个才抢对应的每次有的CPU,解决”并发“问题。
自己写的礼让(个人的理解:礼让就是选择放弃独占CPU,选择和其他线程分享抢到的CPU)
例子题目:打印循环累加1的num,用上同步锁使之不乱序(个人的理解:同步锁的作用等就是让打印的线程启动等后的结果,不是乱序,而是有序,有逻辑和规律的)
:

/**
*
*/
package thread;
import java.util.Random;
public class jinKuang {
public static void main(String[] args) throws Exception{
personClass personClass=new personClass();
new Thread(personClass, "三连").start();
new Thread(personClass, "关注").start();
new Thread(personClass, "诗书画唱").start();
}
}
class personClass implements Runnable{
static int num=0;
@Override
public void run() {
while(true){
synchronized (this) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
num++;
System.out.println(Thread.currentThread()
.getName()+"抢到当前CPU,现在num的值为"+num);
// 个人理解:礼让就是选择放弃独占CPU,
// 选择和其他线程分享抢到的CPU
if(num%5==0){
Thread.yield();
// yield 英[jiːld]
// 美[jiːld]
// v. 出产(作物); 产生(收益、效益等);
// 提供; 屈服; 让步; 放弃; 缴出;
// n. 产量; 产出; 利润;
System.out.println(Thread.currentThread()
.getName()+"进行了礼让");
}
if(num==100){
try {
Thread.sleep(10);
System.out.println("休息一下");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(num==200){
break;
}
}
}
}
}






设计一个线程,模拟买票场景,现有100张票,
使用3个线程进行购买车票
方法一:

package thread;
import java.util.Random;
public class cheZhan {
public static void main(String[] args) throws Exception{
chePiaoClass chePiaoClass=new chePiaoClass() ;
// 下面是省了重命名的部分,直接new实例化:
new Thread(chePiaoClass, "长沙站").start();
new Thread(chePiaoClass, "北京站").start();
new Thread(chePiaoClass,"山东站").start();
}
}
class chePiaoClass implements Runnable{
static int piaoShu=100;//总票数
public void run() {
//票数大于0就可以卖票:
while(piaoShu>0){
// 加synchronized的话,打印出来的才
// 会有从大到小等的顺序等。
// 不然的话,打印出的内容等就会很乱,
// 这是安全性出了问题
synchronized (this) {
// synchronized关键字是用来控制线程同步的,
// 就是在多线程的环境下,
// 控制synchronized代码段不被多个线程同时执行。
//
// synchronized是Java中的关键字,是一种同步锁。
// synchronized:
// 英[ˈsɪŋkrənaɪzd]
// 美[ˈsɪŋkrənaɪzd]
// v. (使) 同步,在时间上一致,同速进行
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(piaoShu>0){
System.out.println(Thread.currentThread()
.getName()+"卖出了第"+piaoShu+"张票");
}piaoShu--;}
}
}
}


方法二:

package thread;
import java.util.Random;
public class piao implements Runnable{
static int num;
static int count;
piao(){
num = 100;
count = 0;
}
@Override
public void run() {
while(num > 0){
synchronized (this) {
try{
Thread.sleep(new Random().nextInt(20));
}catch(Exception e){
e.printStackTrace();
}
if(num > 0){
System.out.println(Thread.currentThread().getName()
+"_____买的票数号码"+num);
num --;
count ++;}
}
}
}
public static void main(String[] args){
piao ticket = new piao();
for(int line = 1 ; line <= 3 ; line ++){
new Thread(ticket,"线程名:线程"+line).start();
}
}
}


创建一个兔子类,一个乌龟类,进行赛跑,目标为10米,
兔子每跑1米休息0.05秒,规定生成随机数,兔子生成的随机数范围为0-5,生成的随机数为3时才开始跑一米,乌龟生成的随机数范围0-20,生成的随机数为13的时候才开始跑一米,乌龟每跑一米休息0.01秒 ,使用线程模拟这个特定龟兔赛跑的过程:

/**
*
*/
package thread;
import java.util.Random;
public class tuZi {
//垃圾回收线程:
// 执行垃圾回收的线程,称为垃圾回收线程。
public static void main(String[] args) throws Exception{
// 2.创建一个兔子类,一个乌龟类,进行赛跑,目标为10米,
// 兔子每跑1米休息0.05秒,兔子的随机范围为0-5,随机到3开始跑,
// 乌龟随机范围0-20,随机到13的时候开始跑,
// 乌龟没跑一米休息0.01秒 ,使用线程模拟
wuGuiClass wuGuiClass=new wuGuiClass();
new Thread(wuGuiClass,"乌龟").start();
tuZiClass tuZiClass=new tuZiClass();
new Thread(tuZiClass,"兔子").start();
}
}
class wuGuiClass implements Runnable{
static int weiZhi=0;//:开始的位置为0米的位置
Random RandomNum=new Random();
public void run() {
while(true){//如果没有到终点一直跑
//乌龟每跑一米休息0.01秒
//设置他们跑的速度就用随机数去设置
int shuzi=RandomNum.nextInt(25);
System.out.println("乌龟生成的随机数为"+shuzi);
//乌龟随机到13之后才开始跑
if(shuzi==13){
weiZhi++;//每次生成的随机数为13时跑一米
System.out.println("乌龟共跑了"+weiZhi+"米");
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//乌龟或者兔子不管谁到终点,都用break停止所有线程
if(wuGuiClass.weiZhi>=10||tuZiClass.weiZhi>=10){
//怎么判断谁赢了
if(wuGuiClass.weiZhi>=10){
System.out.println("乌龟胜利");
}
if(tuZiClass.weiZhi>=10){
System.out.println("兔子胜利");
}
break;
}
}
}
}
class tuZiClass implements Runnable{
static int weiZhi=0;//开始的位置为0米的位置
Random RandomNum=new Random();
public void run() {
while(true){//如果没有到终点一直跑,
//兔子每跑一米休息0.05秒,用上sleep
int tuZiNum=RandomNum.nextInt(5);
System.out.println("兔子生成的随机数为了"+tuZiNum);
if(tuZiNum==3){
weiZhi++;//每次生成的随机数为3时跑一米
System.out.println("兔子共跑了"+weiZhi+"米");
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(wuGuiClass.weiZhi>=10||tuZiClass.weiZhi>=10){
//用两个if判断谁赢了
if(wuGuiClass.weiZhi>=10){
System.out.println("乌龟胜利");
}
if(tuZiClass.weiZhi>=10){
System.out.println("兔子胜利");
}
break;
}
}
}
}



简述线程的生命周期
生命周期由4种状态组成:
1.就绪状态:实例化好了这个线程,但是并没有启动这个线程
2.可运行状态:启动了这个线程,但是这个线程并没有抢到cpu的使用权
3.运行状态:这个线程抢到了cpu的使用权
4.死亡状态:这个线程的代码全部执行完毕之后,就释放掉这个线程
//创建一个兔子类,一个乌龟类,进行赛跑,
//目标为100米,
//(1)兔子每 0.1 秒 5 米的速度,每跑20米休息0.1秒;
//(2)乌龟每 0.1 秒跑 2 米的速度,不休息,乌龟一直跑,使用线程模拟;


JS中回调函数(callback)理解:
字面上理解下来就是,回调就是一个函数的调用过程。那么就从理解这个调用过程开始吧。函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。
其实中文也很好理解:回调,回调,就是回头调用的意思。函数a的事先干完,回头再调用函数b。
举个现实的例子:约会结束后你送你女朋友回家,离别时,你肯定会说:“到家了给我发条信息,我很担心你。”对不,然后你女朋友回家以后还真给你发了条信息。小伙子,你有戏了。
其实这就是一个回调的过程。你留了个函数b(要求女朋友给你发条信息)给你女朋友,然后你女朋友回家,回家的动作是函数a。她必须先回到家以后,函数a的内容执行完了,再执行函数b,然后你就收到一条信息了。
这里必须清楚一点:函数b是你以参数形式传给函数a的,那么函数b就叫回调函数。
也许有人有疑问了:一定要以参数形式传过去吗,我不可以直接在函数a里面调用函数b吗?确实可以。求解中。
解惑:如果你直接在函数a里调用的话,那么这个回调函数就被限制死了。但是使用函数做参数就有下面的好处:当你a(b)的时候函数b就成了回调函数,而你还可以a(c)这个时候,函数c就成了回调函数。如果你写成了function a(){...;b();}就失去了变量的灵活性。
含个人的超级详细的解析:

//创建一个兔子类,一个乌龟类,进行赛跑,
//目标为100米,
//(1)兔子每 0.1 秒 5 米的速度,每跑20米休息0.1秒;
//(2)乌龟每 0.1 秒跑 2 米的速度,不休息,乌龟一直跑,使用线程模拟;
package thread;
import java.util.Random;
import thread.Animal.Calltoback;
public class guiTuGame {
public static void main(String[] args) throws Exception{
// 实例化乌龟和兔子:
//tortoise 英[ˈtɔːtəs]
//美[ˈtɔːrtəs]
//n. 陆龟; 龟;
//————————————
//rabbit 英[ˈræbɪt]
//美[ˈræbɪt]
//n. 兔; 野兔; 兔肉;
//v. 猎兔; 捕兔;
wuGuiDeClass wuGuiDeClass = new wuGuiDeClass();
rabbitClass rabbitClass = new rabbitClass();
// 回调方法的使用,谁先调用calltoback方法,另一个就不跑了
// 回调就是一个函数的调用过程。"call to back":"叫其回来"
// 那么就从理解这个调用过程开始吧。
// 函数a有一个参数,这个参数是个函数b,
// 当函数a执行完以后执行函数b。
// 那么这个过程就叫回调。
// LetLoserStop:让败者停止线程的开启
// 当wuGuiDeClass wuGuiDeClass = new wuGuiDeClass();
// 部分的线程先结束(乌龟赢)时,
// 就会wuGuiDeClass传值
// 到回执函数,就会执行下面的一句的回执函数等,
// calltoback != null,
// 就会执行乌龟类中的 calltoback.win();
// 让兔子类的也再次执行一次回执函数,让兔子停止
LetLoserStop letLoserStopWuGui =
new LetLoserStop(wuGuiDeClass);
// 让兔子的回调方法里面存在乌龟对象的值,可以把乌龟停止stop:
rabbitClass.calltoback =
letLoserStopWuGui;
LetLoserStop letLoserStopRabbit =
new LetLoserStop(rabbitClass);
// 让乌龟的回调方法里面存在兔子对象的值,可以把兔子停止stop:
wuGuiDeClass.calltoback = letLoserStopRabbit;
// 开始跑:
wuGuiDeClass.start();
rabbitClass.start();
}
}
//LetOneStop:让一个停止
//当有一个到达终点的时候,需要让没到终点的乌龟或兔子的线程停止
//,不然的话就会有这里"乌龟获得了胜利"和
//"兔子获得了胜利"都打印出来,所以要用回调函数
//Calltoback,当兔子和乌龟的线程执行时,有一方到达时候,就把
//这一方的参数传到回调函数,让回调函数中声明的stop方法起效果
class LetLoserStop implements Calltoback {
// 动物对象
Animal loserClass;
// 获取动物对象,可以传入兔子或乌龟的实例
public LetLoserStop(Animal loserClass) {
this.loserClass = loserClass;
}
// 让动物的线程停止:
public void win() {
// 线程停止用stop方法:
loserClass.stop();
}
}
class wuGuiDeClass extends Animal {
public wuGuiDeClass() {
setName("乌龟");// Thread的方法,给线程赋值名字
}
// 重写running方法,编写乌龟的奔跑操作
@Override
public void runing() {
// x:乌龟的位移:
int x = 2;
length -= x;
System.out.println("乌龟跑了" +
x + "米,距离终点还有" + length + "米");
if (length <= 0) {
length = 0;
System.out.println("乌龟获得了胜利");
// 让兔子不要在跑了
if (calltoback != null) {
calltoback.win();
}
}
try {
sleep(100);
//每0.1秒跑2米,用sleep实现速度的效果
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class rabbitClass extends Animal {
public rabbitClass() {
setName("兔子");
}
@Override
public void runing() {
//X:兔子位移:
int x = 5;
length -= x;
System.out.println("兔子跑了" + x
+ "米,距离终点还有" + length + "米");
if (length <= 0) {
length = 0;
System.out.println("兔子获得了胜利");
// 给回调对象赋值,让乌龟不要再跑了
if (calltoback != null) {
calltoback.win();
}
}
try {
if ((2000 - length) % 20 == 0) {
// 每20米休息一次,休息时间是0.1秒
sleep(100);
} else { //每0.1秒跑5米
sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//这里用动物类继承了线程类就
//可以有线程类等的特性等,在主函数传兔子类或乌龟类时,就不会报错等
abstract class Animal extends Thread {
public int length = 100;// 比赛长度
public abstract void runing();
@Override
public void run() {
super.run();
while (length > 0) {
runing();
}
}
// 在需要回调数据的地方(两个子类需要),声明一个接口
public static interface Calltoback {
public void win();
}
// 2.创建接口对象
public Calltoback calltoback;
}


创建一个人物类,创建人物张三和李四共同去挖矿,用一个数字5代表金矿,声明随机数,当挖到金矿的时候,当前线程打印“呵呵,挖到金矿了”并且礼让线程,一共挖30次金矿,统计每个人挖到金矿的次数。

/**
*
*/
package thread;
import java.util.Random;
public class jinKuangClass {
public static void main(String[] args) throws Exception{
personClassJinKuang personClass=
new personClassJinKuang();
new Thread(personClass, "张三").start();
new Thread(personClass, "李四").start();
}
}
class personClassJinKuang implements Runnable{
static int num=0;
Random RandomNum=new Random();
@Override
public void run() {
while(true){
int tuZiNum=RandomNum.nextInt(10);
System.out.println("生成的随机数为"+tuZiNum);
synchronized (this) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(tuZiNum==5){
num++;
System.out.println(Thread.currentThread()
.getName()+"抢到当前CPU,现在挖到的金矿次数为"+num+"次");
// 个人理解:礼让就是选择放弃独占CPU,
// 选择和其他线程分享抢到的CPU
if(num%5==0){
Thread.yield();
// yield 英[jiːld]
// 美[jiːld]
// v. 出产(作物); 产生(收益、效益等);
// 提供; 屈服; 让步; 放弃; 缴出;
// n. 产量; 产出; 利润;
System.out.println(Thread.currentThread()
.getName()+"进行了礼让");
}}
if(num==100){
try {
Thread.sleep(100);
System.out.println("休息一下");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(num>=200){
break;
}
}
}
}
}



个人对守护线程的理解:

