JAVA--线程(Thread)_打印线程名称-程序员宅基地

技术标签: 线程  java  

所属包:

                java.lang;

构造方法:

         public Thread();

         public Thread(String name);参数是给线程起个名字

         public Thread(Runnable target);传入要执行的Runnable对象

         public Thread(Runnable target,String name);可以同时传入中间要用“,”隔开

 静态方法:

        static Thread currentThread();获取当前线程

        static void  sleep(long millis);具体数字,毫秒值  1000毫秒=1秒

成员变量:

        private Runnable target;
      

成员方法:

        void start();//启动线程后,会执行run方法中的代码

        void run();线程执行的就是这里的内容

        String getName();获取线程的名字

        void setName(String name);也是用来给线程起一个名字

        State getState();获取线程的状态

调度方式:

                抢占式调度:给每个任务分配的时间不等。(可以理解为线程之间进行争抢,谁抢上就是谁执行任务。)
                分时调度:给每个任务分配的时间是均等的。(可以在任务完添加一个sleep来控制每个线程执行的时间。)

进程和线程:

进程:

        一个应用程序就是一个或者多个进程。


 线程:

        一个进程有一个或者多个线程。

public class Test01 {
	public static void main(String[] args) {
		while(true);
	}
}

 

 

获取线程的名字:Thread.currentThread();+ ?.getName();

public class Test01 {
	public static void main(String[] args) {
		//获取当前线程,执行当前代码的线程
		Thread currentThread = Thread.currentThread();
        //获取线程的名字
		String name = currentThread.getName();
        //打印线程的名字
		System.out.println(name);

	}
}

Runnable接口:

        public abstract void run();

Runnable接口的方式和继承Thread类的方式:建议使用Runnable方式
              a.线程和任务分离,解耦合,提高代码的健壮性。
              b.避免了Java单继承的局限性
              c.线程池里面,只能传入Runnable或者Callable类型的对象,不用new Thread
  
          每一个线程启动后都会有一个栈,各自在各自的栈中执行任务。
          线程的开销比一般对象的开销要大。

 运行一个线程:

第一种方法:

1.先创建一个继承了Thread的的类,并重写run方法(线程执行的任务就是run方法中的代码);

public class SubThread extends Thread{
	@Override
	public void run() {
		//获取当前线程,执行当前代码的线程
		Thread t = Thread.currentThread();
		//获取线程的名称
		String name = t.getName();
		//System.out.println(name+" hello Thread");
		
		for (int i = 0; i < 100; i++) {
			System.out.println(name+"--"+i);
			try {
        //目的是让线程执行完任务睡一会儿,执行速度慢一些,方便我们看效果
				Thread.sleep(100);//单位是毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

try{}catch()是解决异常,详情可见https://so.csdn.net/so/search?spm=1001.2101.3001.7498&q=java%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86&t=&u=&utm_term=java%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86&utm_medium=distribute.pc_toolbar_associateword.none-task-associate_word-opensearch_query-4-java%3Cem%3E%E5%BC%82%E5%B8%B8%3C%2Fem%3E%E5%A4%84%E7%90%86-null-null.nonecase&depth_1-utm_source=distribute.pc_toolbar_associateword.none-task-associate_word-opensearch_query-4-java%3Cem%3E%E5%BC%82%E5%B8%B8%3C%2Fem%3E%E5%A4%84%E7%90%86-null-null.nonecase&request_id=165423633116781685375078&opensearch_request_id=165423633116781685375078https://so.csdn.net/so/search?spm=1001.2101.3001.7498&q=java%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86&t=&u=&utm_term=java%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86&utm_medium=distribute.pc_toolbar_associateword.none-task-associate_word-opensearch_query-4-java%3Cem%3E%E5%BC%82%E5%B8%B8%3C%2Fem%3E%E5%A4%84%E7%90%86-null-null.nonecase&depth_1-utm_source=distribute.pc_toolbar_associateword.none-task-associate_word-opensearch_query-4-java%3Cem%3E%E5%BC%82%E5%B8%B8%3C%2Fem%3E%E5%A4%84%E7%90%86-null-null.nonecase&request_id=165423633116781685375078&opensearch_request_id=165423633116781685375078

2.在测试类中创建该线程对象,并开始任务(?.start();)

public class Test02 {
	public static void main(String[] args) {
		//创建一个子线程
		Thread t = new SubThread();
        //开始任务
		t.start();
		
	}
}

注意:run()与start()的区别:

public class Test02 {
	public static void main(String[] args) {
		//创建一个子线程
		Thread t = new SubThread();
		//t.start();
		
		//如果直接调用run方法,run方法中的代码是由主线程执行的
		t.run();
	}
}

        直接调用run()方法,是主线程main去执行的,没有显示出我们子线程的作用,没有达到我们写线程的目的。

第二种方法:

使用匿名内部类创建Runnable对象;

	public static void main(String[] args) {
		Runnable a = new Runnable(){

			@Override
			public void run() {
				Thread x = Thread.currentThread();
				String name = x.getName();
				for(int i =0;i<100;i++) {
					System.out.println(name+i);
				}
				
			}
			
		};
		Thread b = new Thread(a,"线程一");
		b.start();

	}

}

 线程的并行和并发:

        并行(必须是多核CPU在可以达到):    一个或者多个事件(任务)在同一时间点(同时)执行,好比你可以一般打游戏一边吃饭,同事进行。
        并发():    一个或者多个事件在同一时间段(先后)执行,你有两碗饭,你只有把嘴里的解决了才能吃下一口。

多线程:

        顾名思义是多个线程同时运行

	public static void main(String[] args) {
		Runnable a = new Runnable(){

			@Override
			public void run() {
				Thread x = Thread.currentThread();
				String name = x.getName();
				for(int i =0;i<100;i++) {
					System.out.println(name+i);
				}
				
			}
			
		};
		Thread b = new Thread(a,"线程一");
		b.start();
		new Thread(a,"线程二").start();
	}

}

多线程注意:

         多个线程执行的时候:谁线程值不确定,谁执行多长时间不确定。

线程的安全:

public static void main(String[] args) throws InterruptedException {
        //创建一个集合,使其可以存入20000个元素
		ArrayList<Integer> list = new ArrayList<>(20000);
		
		//通过匿名内部类的方式创建Runnable类型的对象
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					list.add(i);
				}
               //用来判断是否两个线程都执行任务了
				System.out.println("=================");
			}
		};
        //用匿名对象的形式创建两个线程去执行任务
		new Thread(r).start();
		new Thread(r).start();
		
		//用来限制主线程main,防止线程还没执行完,主线程已经执行了sout;
		Thread.sleep(3000);
		System.out.println(list.size());
	}

第一次运行:

第二次运行:

 

 正常下应该是存储20000个,现在会发生丢失问题。

为什么会发生丢失问题?线程安全产生的前提:多个线程访问同一资源(数据)

        线程的执行无非就是这三步;

        

 之所以会发生错误就是线程一拿到数字了,进行第二部+1了,但是还没有执行第三步,任务被线程二抢去了,所以没存上。再等到线程一抢回来,继续存,两个数存了同一个数,就相当于丢了。

	static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				String name = Thread.currentThread().getName();
				for (int i = 0; i < 100; i++) {
					n++;
					System.out.println(name+n);
				}
				
			}
		};
		
		
		new Thread(r,"天线宝宝").start();
		new Thread(r,"花园宝宝").start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}
}

 如何解决线程丢失(上锁):整个的操作不是原子操作:

        在线程一进行操作时,另一个线程二进行等待,只有线程一操作完,释放锁对象,线程二才能抢。

1.使用synchronized代码块

        语法:
                  synchronized(锁对象){//可以是任意类型的对象
                      //写有可能发生线程安全问题的代码
                  }

static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					synchronized (this) {
						n++;
					}
				}
			}
		};
		
		new Thread(r).start();
		new Thread(r).start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}

2.使用synchronized方法

        静态synchronized方法:在static和返回值之间加synchronized关键字
        非静态synchronized方法:在返回值之前加synchronized关键字

        synchronized代码块和方法:代码执行完毕后,自动释放锁

public class Testhah {
	static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					//调用synchronized方法
					add();
				}
			}
		};
		
		new Thread(r).start();
		new Thread(r).start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}
	
	public static synchronized void add() {
		n++;
	}
}

 3.使用Lock锁

        Lock接口:
                  void lock();//上锁
                  void unlock();//开锁
  
                  常用实现类:ReentrantLock
                      构造方法:
                          public ReentrantLock();

public class lulalei {
	static int n = 0;
	public static void main(String[] args) throws InterruptedException {
		Lock lock = new ReentrantLock();
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10000; i++) {
					//上锁
					lock.lock();
					n++;
					//解锁
					lock.unlock();
				}
			}
		};
		
		
		new Thread(r).start();
		new Thread(r).start();
		
		Thread.sleep(3000);
		System.out.println(n);
	}
	
}

 线程的状态:

        NEW:新建状态。创建了一个线程,启动之前处于该状态

public class Test01 {
	public static void main(String[] args) {
		Thread t = new Thread();
		State  s = t.getState();
		System.out.println(s);//NEW
	}
}

         RUNNABLE:可运行状态

public class Test03 {
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				for(;;);
			}
		};
		Thread t = new Thread(r);
		t.start();
		
		Thread.sleep(100);//100毫秒保证子线程开始执行Thread.sleep(1000000);这一行代码了
		//获取并打印线程的状态
		System.out.println(t.getState());
	}
}

 

        BLOCKED:阻塞状态

 

public class Test05 {
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				synchronized(this) {
					for(;;);
				}
			}
		};
		Thread t1 = new Thread(r);
		t1.start();
		Thread t2 = new Thread(r);
		t2.start();
		
		Thread.sleep(100);//100毫秒保证两个子线程已经启动,并开始执行代码了
		//获取并打印线程的状态
		System.out.println(t1.getState());
		System.out.println(t2.getState());
		//获取了锁对象开始执行for循环的线程处于RUNNABLE状态
		//没有获取锁对象的线程处于BLOCKED状态。
	}
}

        WAITING:无限等待状态

public class Test06 {
	public static void main(String[] args) throws InterruptedException {
		Lock lock = new ReentrantLock();
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
					lock.lock();
					for(;;);
			}
		};
		Thread t1 = new Thread(r);
		t1.start();
		Thread t2 = new Thread(r);
		t2.start();
		
		Thread.sleep(100);//100毫秒保证两个子线程已经启动,并开始执行代码了
		//获取并打印线程的状态
		System.out.println(t1.getState());
		System.out.println(t2.getState());
		//获取了锁对象开始执行for循环的线程处于RUNNABLE状态
		//没有获取Lock锁对象的线程处于WAITING状态。
	}
}

 

        TIMED_WAITING:计时等待状态

public class Test04 {
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(1000000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		Thread t = new Thread(r);
		t.start();
		
		Thread.sleep(100);//100毫秒保证子线程开始执行Thread.sleep(1000000);这一行代码了
		//获取并打印线程的状态
		System.out.println(t.getState());
	}
}

 

        TERMINATED:消亡状态

public class Test02 {
	public static void main(String[] args) throws InterruptedException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		};
		Thread t = new Thread(r);
		t.start();
		
		Thread.sleep(1000);//1000毫秒子线程一定把任务执行完毕了
		//获取并打印线程的状态
		System.out.println(t.getState());
	}
}

 

线程的通信:线程和线程之间的沟通

        等待唤醒机制:

                        Object类:

               void wait();//就会让线程进入等待状态。WAITING状态
              void wait(long time);//调用该方法,会让线程进入计时等待状态。TIMED_WAITING
              void notify();//调用该方法,会让线程醒来,接着执行任务。
              void notifyAll();//调用该方法,会唤醒当前锁对象上等待的所有线程

注意事项:

        1.这些方法都必须写在synchronized代码块或者synchronized方法中           

        2.调用这些方法的对象,必须和锁对象一致。

        3.  t.notify方法,只能唤醒t锁对象上等待的线程

        4.  调用了wait(不论是否有参数)方法后,会自动释放锁对象。

例子:

1.创建一个Fruit类

public class Fruit {
	private int stock;
	public int getStock() {
		return stock;
	}
	public void setStock(int stock) {
		this.stock = stock;
	}
	
}

2.官网线程类

public class NetShop implements Runnable{
	private Fruit f;
	public NetShop(Fruit f) {
		super();
		this.f = f;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(f) {
				//判断是否退出循环
				if(f.getStock()<=0) {
					break;
				}
				//偶数份,官网卖
				if(f.getStock()%2==0) {
					//每卖一份,库存减1
					f.setStock(f.getStock()-1);
					System.out.println("官网正在卖出第"+(100-f.getStock())+"份,还剩余"+f.getStock()+"份");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//唤醒当前锁对象上等待的线程
					f.notify();
				}else {
					//奇数份,官网进入等待状态
					try {
						f.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

3.实体店线程类

public class FrontShop implements Runnable{
	private Fruit f;
	public FrontShop(Fruit f) {
		super();
		this.f = f;
	}

	@Override
	public void run() {
		while(true) {
			synchronized(f) {
				//判断是否退出循环
				if(f.getStock()<=0) {
					break;
				}
				//奇数份,实体店卖
				if(f.getStock()%2==1) {
					//每卖一份,库存减1
					f.setStock(f.getStock()-1);
					System.out.println("实体店正在卖出第"+(100-f.getStock())+"份,还剩余"+f.getStock()+"份");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//唤醒当前锁对象上等待的线程
					f.notify();
				}else {
					//偶数份,实体店进入等待状态
					try {
						f.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

4.测试类

public class Test01 {
	public static void main(String[] args) {
		//创建Fruit类型的对象
		Fruit f = new Fruit();
		f.setStock(100);
		
		//创建官网和实体店类型的对象
		Runnable r1 = new NetShop(f);
		Runnable r2 = new FrontShop(f);
		
		//创建两个线程,分别指向这两个任务
		new Thread(r1).start();
		new Thread(r2).start();
	}
}

 注意:

        我们做这个题要明确两点:

        1.这两边需要一个共同的锁对象
        2.根据库存去判断谁该执行了,谁该等待了

线程池:

        简单来说就是一个存放线程的池子,线程执行完任务会回到池子里面等待下一个任务的到来,提高效率。

        1.提高响应速度。预先创建好了线程,只等任务过来执行。

        2.降低资源消耗。线程池中的线程,执行完任务后,又返回到线程池中,下一个任务到来后可以继续使用该线程。

        3.提高线程的可管理性。一个线程大约需要消耗1M的空间,线程池可以设置最大线程的数量。

Executors类:

        static ExecutorService newFiexdThredadPool(int nThread);

ExecutorService接口:

        void execute(Runnable r);//执行任务
        <T> Future<T> submit(Callable<T> c);//执行任务
        Future<?> submit(Runnable r);//执行任务
        void shutdown();//关闭线程池

public class Test01 {
	public static void main(String[] args) {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		};
		
		//创建一个固定线程池对象
		ExecutorService es = Executors.newFixedThreadPool(2);
		//执行任务
		es.execute(r);
		//关闭线程池
		es.shutdown();
	}
}

 

下面是如果有多个任务线程池怎么运行:

public class Test02 {
	public static void main(String[] args) {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		
		//创建一个固定线程池对象
		ExecutorService es = Executors.newFixedThreadPool(2);
		//执行任务
		es.execute(r);
		es.execute(r);
		es.execute(r);
		//关闭线程池
		es.shutdown();
	}
}

         从结果,可以看出来,先执行任务的那个把任务执行完,接着把第三次任务执行了,后执行任务的,执行完任务就回到了线程池。

 

Future<T>接口

        T get();//必须等子线程把任务执行完成,return以后才可以获取返回的结果。

Callable<T>接口(与Runnable很像):

        T call();

public class Test04 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println(Thread.currentThread().getName());
			}
		};
		
		//创建一个固定线程池对象
		ExecutorService es = Executors.newFixedThreadPool(2);
		Future<?> future = es.submit(r);
		Object result = future.get();//null
		System.out.println(result);
		//关闭线程池
		es.shutdown();
	}
}

        

 可以看出来Runnable没有返回值,所以就不用接收了。

public class Test03 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Callable<String> c = new Callable<String>() {
			@Override
			public String call() throws Exception {
				//call方法中的代码是某个子线程执行的
				System.out.println(Thread.currentThread().getName());
				Thread.sleep(5000);
				return "test callable";
			}
		};
		
		//创建一个固定线程池对象
		ExecutorService es = Executors.newFixedThreadPool(2);
		Future<String> future = es.submit(c);
		
		//这行代码是主线程执行的
		String result = future.get();
		System.out.println(result);
		//关闭线程池
		es.shutdown();
	}
}

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zailalaniubi/article/details/125130696

智能推荐

网络由三十台计算机组成,自考网络教育计算机组成原理作业考试题及答案三套.doc...-程序员宅基地

文章浏览阅读85次。自考网络教育计算机组成原理作业考试题及答案三套计算机组成原理 一、单项选择题(本大题共100分,共 40 小题,每小题 2.5 分)1. CPU从主存取出一条指令并执行该指令的时间叫做( ) A. 机器周期 B. 指令周期 C. 时钟周期 D. 总线周期2. 同步控制是( ). A. 只适用于CPU控制的方式 B. 只适用于外围设备控制的方式 C. 由统一时序信号控制的方式 D. 所有指令控制时间..._30台计算机组成的网络

封印者与登录服务器的连接已中断,封印者闪退掉线黑屏怎么办 无法登陆如何解决...-程序员宅基地

文章浏览阅读1.1k次。封印者闪退掉线黑屏怎么办?游戏无法登陆如何解决?封印者是最近不删档的游戏,受到了不少玩家喜爱。有不少玩家反映在玩封印者出现了闪退等问题,那么如何解决上述问题呢?下面就和说玩网小编一起去看看吧。1、网络问题,有时候网络不好,链接不上游戏,就会出现闪退。解决方法:建议在玩家在WIFI环境下开始游戏,或者是3G/4G等网络环境较好的地方开始游戏。2、玩家手机内存不够,玩家手机的内存不够了,就会出现卡顿、..._封印者闪退解决方案

sentinel springboot版本 使用_springboot 和sentinel对应版本号-程序员宅基地

文章浏览阅读1.9k次。pom<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>0.9.0.RELEASE<..._springboot 和sentinel对应版本号

人工智能-即将引发创业热潮-程序员宅基地

文章浏览阅读197次。自2017年7月国务院发布《新一代人工智能发展规划》并提出三步走规划以来,已先后有多个省市出台相应的政策措施。 Python,最接近人工智能的语言!将被纳入高考内容! 浙江省信息技术课程改革方案已经出台,Python确定进入浙江省信息技术高考,从2018年起浙江省信息技术教材编程..._人工智能创业潮

ideaSSM 高校公寓交流员管理系统bootstrap开发mysql数据库web结构java编程计算机网页源码maven项目-程序员宅基地

文章浏览阅读1.3k次,点赞19次,收藏25次。一、源码特点idea 开发 SSM 高校公寓交流管理系统是一套完善的信息管理系统,结合SSM框架和bootstrap完成本系统,对理解JSP java编程开发语言有帮助系统采用SSM框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。前段主要技术 bootstrap.css jquery后端主要技术 SpringMVC spring mybatis数据库 mysql开发工具 IDEA JDK1.8 TOMCAT 8.5。

C语言实现顺序表_顺序表c语言实现-程序员宅基地

文章浏览阅读1.6k次,点赞36次,收藏39次。1.2 SeqList.c1.3 test.c二、顺序表的实现2.1 顺序表创建一个顺序表结构体,成员包含顺序表地址、长度、大小,用于创建顺序表变量。 将顺序表变量的地址传参,通过指针接收对顺序表的顺序表数组初始化为空,长度为0,大小为0。同样传地址,要先断言指针是否为空,不然会出异常。然后判断顺序表大小是否为0,为0则代表顺序表中没有有效元素,打印提示,并返回函数,如果大于0,则有元素,从下标0开始,打印size个顺序表元素,并用空格相隔。当我们结束程序_顺序表c语言实现

随便推点

利用tkinter制作一个用户界面:开始研究界面的零件及细节_python tkinter 注册页面-程序员宅基地

文章浏览阅读555次,点赞2次,收藏4次。导入:我想作为一名Python程序猿,大家对于tkinter大家应该不陌生了吧,那么在接下几篇博文里我将跟大伙一起来实现tkinter的用户登录界面。注意:该界面没有注册哦~tkinter的基础:想要先实例化一个窗口我们就得学会以下代码:import tkinter as tkwindow = tk.Tk()window.title("xxx")window.geometry("300x500")#注意,引号中的窗口大小必须用"x",而不是“*”window.mainloop()运行了_python tkinter 注册页面

How Firewalls (Security Gateways) Handle the Packets? (Traffic Flow)-程序员宅基地

文章浏览阅读167次。Different firewall (security gateway) vendor has different solution to handle the passing traffic. This post compiles some useful Internet posts that interpret major vendors’ solutions including:1. C..._traffic@flow: nat:

基础设施即代码(Infrastructure as Code)-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏7次。Infrastructure as Code(IaC)是一种IT基础设施管理流程,它将DevOps软件开发的最佳实践应用于云基础设施资源的管理。_infrastructure as code

Android二维码的创建、解析及NotFoundException_no multiformat readers were able to detect the cod-程序员宅基地

文章浏览阅读1.8k次。本篇博客主要记录一下Android生成及解析二维码的基本方法, 同时记录一下遇到的NotFoundException及对应解决方法。_no multiformat readers were able to detect the code.

java里nim游戏问题_使用Minimax算法的NIM游戏和AI玩家 - AI会失去动作-程序员宅基地

文章浏览阅读182次。我已经完成了与人类玩家和AI玩家一起编写NIM游戏的任务 . 该游戏是“Misere”(最后一个必须选择一根棒) . 人工智能应该是使用Minimax算法,但它正在进行移动,使其失去更快,我无法弄清楚为什么 . 我已经连续几天走到了尽头 . Minimax算法的目的是不输,如果它处于失败状态,延迟失去尽可能多的动作,对吧?考虑以下:NIMBoard board =新的NIMBoard(34,2)..._nim的 misere版本

MyBatis 中常用的 Mapper 相关注解和技巧,包括 @Select/@Insert/@Update/@Delete 和 @Options,并给出一些常见的优化方法_mapper @select-程序员宅基地

文章浏览阅读1.6k次。Mapper 是 MyBatis 中的一个重要概念,它用于封装复杂的 SQL 和参数映射关系,降低数据访问层与业务逻辑层之间的耦合度,方便后期维护和扩展。本系列教程主要基于 MyBatis3.x版本进行讲解,对 MyBatis-spring、MyBatis-mybatis、MyBatis-generator 等其他框架也会有所涉及。在 MyBatis 中,Mapper 是一个接口,这个接口提供了若干个方法,这些方法对应了我们执行数据库操作时需要执行的 SQL 语句或存储过程。_mapper @select

推荐文章

热门文章

相关标签