概述
一:多线程:一个程序中有多条进程;
单线程:一个程序中有一条进程
#java虚拟机是多线程程序吗?
是多线程程序,因为JAVA虚拟机中有垃圾回收器,该作用是为了防止内存溢出;当调用程序的时候,至少会开启两条进程,首先会开启main主线程,然后会调用垃圾回收器,回收掉不用的成员变量和没有更对引用的对象;
二:如何实现多线程程序:
要想实现多线程程序,就必须要创建一个进程,而创建进程,就需要调用系统资源创建,JAVA语言中不会调用系统资源进行创建进程,但是C/C++可以,所以JAVA语言是间接通过C/C++调用系统资源创建进程来实现多线程的程序
三:多线程程序的实现方式一:
1. 自定义资格类,该类继承自Thread类
2. 在该类中重写run()方法
3. 在当前类(主线程类)中创建该类的实例化对象
#使用继承的方式实现多线程的启动
package ThreadText;
/**
* 需求:使用继承的方法来实现多线程程序
* */
public class ThreadText_01 {
public static void main(String[] args) {
MyThread my1=new MyThread();//创建子实现类的对象
MyThread my2=new MyThread();
my1.setName("线程一");
my2.setName("线程二");
//启动线程
my1.start();
my2.start();
}
}
class MyThread extends Thread{
public void run(){//重写thread类中的run()方法
for(int i=1;i<10;i++){
System.out.println(getName() + "---" + i);
}
}
}
#注意:
(1)该方法在启动线程的时候调用的是start()方法,二不是run()方法,调用start()方法的实质就是通过JAVA虚拟机调用run()方法
(2) 该多线程一旦被启动,就不能再次调用
(3) 由于该类中原本就有getName()方法,所以在子实现类中应该避免定义name成员,同时避免该类中采用getName()方法调用该成员名字;该方法是用来获取当前线程的名称
四:Thread类中的成员方法:
1. 线程终止:
public final void join()等待该线程终止。(该方法是在启动该线程之后执行)该方法会跑出异常: throws InterruptedException
2. 返回线程的优先级:
public final int getPriority()返回线程的优先级。
public static final int MAX_PRIORITY 10 :最大优先级(优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性!)
public static final int MIN_PRIORITY 1 :最小优先级
public static final int NORM_PRIORITY 5 :默认优先级
3. 暂停线程:
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权
#多线程的join(),yield()和 getPriority()方法的综合应用:
package ThreadText;
/**
*需求:使用Thread类的join(),yield()和 getPriority()方法执行多线程程序
* */
public class ThreadText_02 {
public static void main(String[] args) {
Mythread my1=new Mythread();
Mythread my2=new Mythread();
my1.setName("线程一");
my2.setName("线程二");
my1.setPriority(10);//将线程一的优先级设置为最大
my2.setPriority(1);//将线程二的优先级设置为最小
my1.start();//启动线程一
try {
my1.join();
} catch (InterruptedException e) {
System.out.println("这里终止了线程一");
// e.printStackTrace();
}//终止该线程
my2.start();
}
}
class Mythread extends Thread{
public void run(){
for(int i=0;i<20;i++){
System.out.println(getName() + "---" +i);
Thread.yield();//终止当前正在运行的线程
}
}
}
4. 线程停止:
public final void stop():强迫线程停止执行
public void interrupt()中断线程。 表示中断线程一种状态
5. 线程睡眠
public staticvoid sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行;该方法会跑出异常: throws InterruptedException
#使用Thread类的sleep()方法,进行执行多线程程序:
package ThreadText;
/**
* 需求:使用多线程的stop()方法和sleep()方法执行多线程程序
* */
public class ThreadText_03 {
public static void main(String[] args) {
MyThread1 my1=new MyThread1();
MyThread1 my2=new MyThread1();
my1.setName("线程一");
my2.setName("线程二");
//启动线程
my1.start();
//给线程一添加睡眠时间
}
}
class MyThread1 extends Thread{
public void run(){
for(int i=1;i<10;i++){
System.out.println(getName() + "---" + i);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
System.out.println("此方法是对线程调用睡眠模式");
// e.printStackTrace();
}
}
}
}
6. 守护线程
public final void setDaemon(boolean on) on指定true,就是设置守护线程...
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
#使用守护线程执行多线程程序:
package ThreadText;
/**
* 需求:使用守护线程执行多线程程序
* 1.自定义一个类,该类继承自Thread类,
* 2.在该类中重写run()方法
* 3.在主线程中,创建两个子实现类的对象,
* 4.调用setName()方法,分别给两个子线程命名为关羽和张飞,
* 5.用Thread类调用currentThread()方法再调用setName()方法,将主线程的名称改为刘备
* 6.在主线程和子实现类中分别定义for循环来获取每个线程的名称
* */
public class ThreadText_04 {
public static void main(String[] args) {
MyThread2 my1=new MyThread2();
MyThread2 my2=new MyThread2();
my1.setName("关羽");
my2.setName("张飞");
//设置守护线程
my1.setDaemon(true);
my2.setDaemon(true);//该方法中的参数设置为true表示设置为守护线程
//启动线程
my1.start();
my2.start();
//通过Thread类给获取主线程的名称,并且给其命名
Thread.currentThread().setName("刘备");
//定义一个for循环,来遍历主线程的同时获取每一个子线程的名称
for(int i=1;i<5;i++){
System.out.println(Thread.currentThread().getName() + "--" + i);//主线程结束后,子线程并不会立即释放,
}
}
}
class MyThread2 extends Thread{
public void run(){
for(int i=0;i<20;i++){
System.out.println(getName() + "---" + i);
}
}
}
五: 多线程实现的第二种方式(该方法使用接口的形式)
1.开发步骤
(1)自定义一个类,该类实现接口Runnable接口
(2)在该类中重写接口中的run()方法
(3)在主线程中创建子实现类的实例化对象
(4)在创建Thread类的对象,同时将上述的对象当做参数进行传递
(5)分别启动线程
#用接口的方法执行多线程程序:
package ThreadText_02;
/**
* 需求:使用自定义类实现接口的方法来执行多线程程序
* */
public class ThreadText_01 {
public static void main(String[] args) {
MyThread my=new MyThread();//创建自定义类的对象
//创建Thread类的对象
Thread t1=new Thread(my,"线程一");//该方法的第二个参数指明线程的名称
Thread t2=new Thread(my,"线程二");
//启动线程
t1.start();
t2.start();
}
}
class MyThread implements Runnable{
public void run() {
for(int i=1;i<10;i++){
System.out.println(Thread.currentThread().getName() + "---" +i);
}
}
}
#在此执行多线程程序中,获取线程名称的方法使用Thread.currentThread().getName()方法来获取当前线程的名称
六:多线程的线程安全问题:
1. 检验多线程安全问题的标准
(1) 当前是否是一个多线程环境
(2) 多线程中是否有共享数据
(3) 是否有多条语句对共享数据进行操作
2. 对于多线程程序,加入延迟操作会出现线程安全问题
#对于多线程问题加入延迟操作,可能会出现的问题(电影院售票案例)
1) 一张票可能被卖多次
2) 可能会出现负数
这是由于多线程的延迟操作和线程随机性导致的
package ThreadText_02;
/**
* 需求:使用自定义类实现接口的形式来实现电影院卖票:
* 1.创建自定义类MyThread2,该类实现接口Runnable
* 2.在该方法中定义一个成员变量tickles=100
* 3.定义一个while循环,模拟电影院一直有票
* 4.再加入睡眠时间1秒,
* 5.在主线程中创建该类的实例化对象
* 6.再创建Thread类的三个对象,共同将上述的对象当做参数传入该方法中,再分别定义三个线程的名称为窗口1,2,3
* 7.启动线程,最后输出窗口出票情况
* */
public class ThreadText_02 {
public static void main(String[] args) {
myThread my=new myThread();
Thread t1=new Thread(my,"窗口一");
Thread t2=new Thread(my,"窗口二");
Thread t3=new Thread(my,"窗口三");
//]启动多线程
t1.start();
t2.start();
t3.start();
}
}
class myThread implements Runnable{
private static int tickles=100;
public void run() {
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("该方法是将给系统加入1秒的睡眠时间");
// e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + tickles-- + "张票");
}
}
}
3. 优化改进:需要在多条语句对共享数据操作上进行改进:使用同步代码块将多条语句对共享数据的操作包起来;例: synchronized(同步锁对象){ 多条语句对共享数据操作代码}
4. 同步锁对象:应该每一个线程都要使用这个锁对象(同步锁);该对象可以是任意类的对象
#使用同步代码块改进后的电影院发票程序:
package ThreadText_02;
/**
* 使用同步锁对象优化改进电影院售票
* */
public class ThreadText_03 {
public static void main(String[] args) {
SellTickles st=new SellTickles();
Thread t1=new Thread(st,"窗口一");
Thread t2=new Thread(st,"窗口二");
Thread t3=new Thread(st,"窗口三");
//启动多线程
t1.start();
t2.start();
t3.start();
}
}
class SellTickles implements Runnable{
private int tickles=100;
Object obj=new Object();//创建同步锁对象
public void run() {
while(true){
synchronized(obj){
if(tickles>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.out.println("该方法是模拟售票系统,每卖出一张票后,让系统睡眠0.1秒");
// e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + (tickles--) + "张票");
}
}
}
}
}
5. Jdk5以后Java提供了一个更具体的锁对象:Lock
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作; Lock是一个接口,所以它在使用的是 ReentrantLock子实现类
成员方法: public void lock()获取锁。
publicvoid unlock()试图释放此锁
#使用具体锁对存在安全问题的多线程程序执行:
package ThreadText_02;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadText_04 {
public static void main(String[] args) {
SellTickle st=new SellTickle();
//创建Thread类对象
Thread t1=new Thread(st,"窗口一");
Thread t2=new Thread(st,"窗口二");
Thread t3=new Thread(st,"窗口三");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
class SellTickle implements Runnable{
private int tickles=100;
//创建所对象
Lock lock=new ReentrantLock();//创建具体锁对象
public void run() {
while(true){
lock.lock();
if(tickles>0){
try {
Thread.sleep(100);
} catch(InterruptedException e) {
System.out.println("该方法是模拟系统售出票之后,睡眠0.1秒");
// e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售" + (tickles--) + "张票!");
}
}
}
}
6. 使用同步机制可以解决多线程的安全问题,但是自身也会有弊端:
1) 同步---->执行效率低(每一个线程在抢占到CPU的执行权,会去将(门)关闭,别的线程进不来)
2) 容易出现死锁现象: 两个或者两个以上的线程出现了互相等待的情况,就会出现死锁!
#使用多线程来模拟死锁线程:
package ThreadText_02;
/**
* 需求:使用同步代码模拟线程等待(死锁线程)
* 1.自定义一个类,该类继承自Thread类,在该类中定义一个标记标签flag
* 再重写Thread类的run()方法
* 2.自定义一个创建所对象类的类LockDemo,在该类中创建两个同步所对象,分别为lock1和lock2
* 3.在主线程中创建自定义类的对象,分别传入参数true和false参数,然后启动线程
* */
public class ThreadText_05 {
public static void main(String[] args) {
MyThreadDemo m1=new MyThreadDemo(true);
MyThreadDemo m2=new MyThreadDemo(false);
//启动多线程
m1.start();
m2.start();
}
}
class MyThreadDemo extends Thread{
private boolean flag;
public MyThreadDemo(boolean flag) {
this.flag=flag;
// TODO Auto-generatedconstructor stub
}
//重写run()方法,
public void run(){
if(flag){
synchronized(LockDemo.lock1){
System.out.println("这是同步锁lock1!");
synchronized(LockDemo.lock2){
System.out.println("这是同步锁lock2!");
}
}
}else{
synchronized(LockDemo.lock2){
System.out.println("这是同步锁lock2!");
synchronized(LockDemo.lock1){
System.out.println("这是同步锁lock1!");
}
}
}
}
}
class LockDemo {
//定义两个同步锁对象
static LockDemo lock1=new LockDemo();
static LockDemo lock2=new LockDemo();
}
#使用多线程模拟消费者生产者模式:
package ThreadText_02;
/**
* 需求:使用多线程模拟生产者消费模式,
* 1.自定义一个生产者类(SetStudent)该类实现接口Runnable,
* 再自定义一个消费者类(GetStudent)该类也实现Runnable接口,在SetStudent类中定义成员信息,
* 在GetStudent类中获取成员信息,同时都要重写run() 方法
* 2.在主线程中国创建Student类对象,再分别创建SetStudent类和getStudent类的对象,将上述
* 获取到的学生对象当做参数进行传入
* 3.再分别创建两个Thread类对象,将SetStudent类和getStudent类的对象当做参数进行传入
* 4.需要注意的是,需要在主线程中创一个公共的Student类对象,防止每个线程创建自己的Student类的对象,这样最后输出的结果为null值
*
*
* */
public class ThreadText_06 {
public static void main(String[] args) {
Student s=new Student();
//创建SetStudent类对象
SetStudent st=new SetStudent(s);
//创建GetStudent类对象
GetStudent gt=new GetStudent(s);
//创建两个Thread类对象
Thread t1=new Thread(st);
Thread t2=new Thread(gt);
t1.start();
t2.start();
}
}
class Student{
int age;
String name;
}
class SetStudent implements Runnable{
private Student s;
public SetStudent(Student s) {
this.s=s;
}
public void run(){
s.age=30;
s.name="wangqiang";
}
}
class GetStudent implements Runnable{
private Student s;
public GetStudent(Student s) {
this.s=s;
}
public void run(){
System.out.println(s.name + "的年龄为" + s.age);
}
}
7. 线程组
public ThreadGroup(String name): 构造一个新线程组。新线程组的父线程组是目前正在运行线程的线程组。
#多线程的线程组应用:
package ThreadText_02;
/**
* 需求:在多线程程序中创建一个线程组
* */
public class ThreadText_07 {
public static void main(String[] args) {
method2();
method1();
}
private static void method2() {
//创建自定义类对象
MyThread4 mt=new MyThread4();
//创建Thread类对象
Thread t1=new Thread(mt,"线程一");
Thread t2=new Thread(mt,"线程二");
//启动线程
t1.start();
t2.start();
ThreadGroup gp1 = t1.getThreadGroup();
ThreadGroup gp2 = t2.getThreadGroup();
System.out.println(gp1.getName() + "----" + gp2.getName());
}
private static void method1() {
ThreadGroup tg=new ThreadGroup("这是一个线程组:");//创建线程组对象
//创建自定义类对象
MyThread4 mt=new MyThread4();
//创建Thread类对象
Thread t1=new Thread(tg,mt,"线程一");
Thread t2=new Thread(tg,mt,"线程二");
//获取线程子线程所在线程组的名称
ThreadGroup gp1 = t1.getThreadGroup();
ThreadGroup gp2 = t2.getThreadGroup();
System.out.println(gp1.getName() + "----" + gp2.getName());
}
}
class MyThread4 implements Runnable{
public void run() {
for(int i=0;i<20;i++){
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
六, 多线程程序的实现方式3:(使用Executors类来创建线程池对象,来进行异步提交)
1. 创建自定义类对象,该类实现接口Runnable接口,同时在该类中重写该接口中的run()方法.
2. 在主线程中通过Executors类创建线程池对象,并指明该线程池中有几个子线程,
3. 创建两个自定义类的对象
4. 通过线程池对象调用submit()方法,将上述两个对象参数传入,进行异步提交任务
5. 调用Executors类的shutdown()方法,来关闭线程池对象
(1).好处:节约成本; 很多子线程调用完毕不会立即被回收掉,而是会回到线程池中被多次利用!
(2). JDK5新增了一个Executors工厂类来产生线程池
(3)成员方法: public static ExecutorService newFixedThreadPool(int nThreads) Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
例:ExecutorService es=Executors.newFixedThreadPool();
(4)提交任务:
es.submit();
(5)关闭线程池
es.shutdown()
#多线程中使用线程池提交多项任务:
6. package ThreadText_02;
7. importjava.util.concurrent.ExecutorService;
8. importjava.util.concurrent.Executors;
9. /**
10. * 需求:多线程中使用线程池提交多项任务,并且关闭线程池
11. * */
12.public class ThreadText_08 {
13. public static void main(String[]args) {
14. //创建线程池对象
15. ExecutorServicepool=Executors.newFixedThreadPool(2);//该方法中的参数指明线程池中有几个子线程
16.
17. //创建自定义类对象
18. ExecutorsDemoed1=new ExecutorsDemo();
19. ExecutorsDemoed2=new ExecutorsDemo();
20.
21. //使用线程池提交两个子线程
22. pool.submit(ed1);
23. pool.submit(ed2);
24.
25. //关闭线程池
26. pool.shutdown();
27. }
28.}
29.class ExecutorsDemo implements Runnable{
30. public void run(){
31. for(int i=0;i<10;i++){
32. System.out.println(Thread.currentThread().getName()+ "--" + i);
33. }
34. }
35.}
#使用线程池解决线程求和问题:
package CallableText;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 需求:使用callable接口中的call()方法对线程进行求和:
* 1.自定义一个类(MyCallabe)该类实现接口Callable<Intager>并指明其泛型为Integer类型
* 2.在自定义类中定义一个成员变量number,通过有参构造给其赋值,在该类中重写call()方法,该方法会跑胡异常
* 3.在主线程中常见线程池对象
* 4.再通过Executors类调用submit()方法,参数传入自定义类的有参构造,并给number赋值
* 5.关闭线程池对象
* */
public class CallableText_01 {
public static void main(String[] args) throws InterruptedException,ExecutionException {
//创建线程池对象
ExecutorService pool=Executors.newFixedThreadPool(2);//该方法中的参数指明线程池中有几个子线程
//调用submit()方法返回Future类的对象
Future<Integer> f1 = pool.submit(new MyCallable(20) );
Future<Integer> f2 = pool.submit(new MyCallable(10) );
//通过上述对象,然后调用Future类的get()方法,返回具体的结果
Integer i1= f1.get();
Integer i2 = f2.get();
//输出结果
System.out.println("线程一的值:" + i1);
System.out.println("线程二的值:" + i2);
//关闭线程池
}
}
class MyCallable implements Callable<Integer>{
private int number;
public MyCallable(int number) {
this.number = number;
}
public Integer call() throws Exception {
int sum=0;
for(int i=1;i<number;i++){
sum += i;
}
return sum;
}
}
七,Timer类:
该类的成员方法:
#在指定的时间点递归删除指定文件夹下的文件及文件夹:
package TimerText;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* 需求:在指定的时间删除我们的指定目录(递归删除e:\盘下FileDemo_01中的文件和文件夹
* 1.自定义一个类(DeleteDocuments)该类继承自TimerTask类
* 2.在该类中重写该接口的run()方法,再改方法中调用FIle类的构造方法用来封装数据源
* 3.再在该方法中定义一个递归删除文件及文件夹的方法delete,在该方法中,参数为上述的File类的对象,
* 用上述封装好的数据源调用isFiles()方法来封装文件夹中的文件及文件夹返回File类型的数组
* 4.对该File类型的对象数组进行非空判断,然后遍历该数组中的元素
* 5.加入if()语句然后调用Fiel类的isDirectory()判断该文件是否是文件夹,如果是,继续递归调用delete()方法
* 如果不是文件夹,直接调用File类的delete()方法,将该文件删除,并且输出该文件的名称
* 6.在if()判断外面再次调用file类的delete()方法,此时用来删除该盘符下的文件夹
* 7.同时输出删除的文件夹名称
* 8.在主线程中定义Timer类,再定义一个String类型的日期,通过SimplDateFormate对象,格式化为Date 类型的日期
* 9.在调用Timer类的schedule(),在指定的时间点执行指定的任务
* */
public class TimerText_01 {
public static void main(String[] args) throws ParseException {
Timer t=new Timer();
String StrDate="2017-12-613:45:00";
//创建SimpleDateFormat对象
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=sdf.parse(StrDate);
//调用Timer类的schedule()方法
t.schedule(new DeleteDocuments(), date);
}
}
class DeleteDocuments extends TimerTask{
@Override
public void run() {
File file=new File("e:\FileDemo_01");//创建File类对象封装数据源
//定义递归删除文件的方法
delete( file);
}
private void delete(File file) {
//用File类的listFiles()方法来封装文件元素4
File[] listFiles = file.listFiles();//返回File类型的数组
//判断该数组是否为空
if(listFiles!=null){
for(File f:listFiles){
if(f.isDirectory()){
delete(f);
}else{
System.out.println(f.getName() + "该文件被删除了" + f.delete());
}
//在if()语句外调用delete()方法,用来删除文件夹
System.out.println(f.getName() + "该文件夹被删除了" + f.delete());
}
}
}
}
#Timer类的Schudle()方法综合应用:
package TimerText;
import java.util.Timer;
import java.util.TimerTask;
/**
* 需求:Timer类的Schsdule()方法的综合应用:
* 1.自定义一个类,该类继承自TimerTask,并且在该类中重写run()方法,在该方法中定义一个输出语句
* 2,在测试类中创建Timer类对象,
* 3.用上述的Timer类的对象调用public void schedule(TimerTask task, long delay, long period)参数一指明执行的操作,
* 参数二指明系统过多久之后执行该任务,参数三指明每隔多久之后重新执行该任务
* */
public class TimerText_02 {
public static void main(String[] args) {
Timer t=new Timer();//创建Timer类的对象
//调用Schsdule()方法
t.schedule(new MyTask(), 3000, 1500);
}
}
class MyTask extends TimerTask{
public void run(){
System.out.println("bom...大爆炸!");
}
}
八;多线程中匿名内部类的实现:
package ThreadText;
/**
* 需求:多线程中匿名内部类的方法
* 1.继承自Thread类的方法实现多线程的匿名内部类
* 2.实现接口Runnable接口的方法实现匿名内部类的方法
* */
public class ThreadText_05 {
public static void main(String[] args) {
//方法一:继承自Thread类
// new Thread(){
// public void run(){
// for(int i=1;i<10;i++){
// System.out.println(getName() + "---" + i);
// }
// }
// }.start();
//方法二,实现接口Runnable
new Thread(new Runnable(){
public void run() {
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}).start();
}
}
九:IO流版模拟用户注册登录:
测试类:
import java.util.Scanner;
import Impl.UserImpl;
import User.User;
import UserDao.UserDao;
/**
* 该类是测试类:在该类中进行键盘录入,让用户进行选择:登录和注册
* */
public class UserText {
public static void main(String[] args) {
while(true){
System.out.println("----------------请您作出以下选择-----------------");
System.out.println("1---登录");
System.out.println("2---注册");
System.out.println("3---退出");
Scanner Sc=new Scanner(System.in);
System.out.println("请选择:");
String Choice=Sc.nextLine();
UserDao ud=new UserImpl();//创建接口的子实现类对象
switch(Choice){
case "1":
System.out.println("请输入用户名:");
String username=Sc.nextLine();
System.out.println("请输入密码:");
String password=Sc.nextLine();
boolean isLogin = ud.IsLogin(username, password);
if(isLogin){
System.out.println("恭喜您,登录成功!");
System.exit(0);
}else{
System.out.println("您输入的信息有误,请重新输入!");
}
break;
case "2":
System.out.println("请输入用户名:");
String NewUserName=Sc.nextLine();
System.out.println("请输入密码:");
String NewPassWord=Sc.nextLine();
User u=new User();
u.setUserName(NewUserName);
u.setPassWord(NewPassWord);
ud.Rigest(u);//将上述的User类的对象数据传入该方法
System.out.println("恭喜你,注册成功!");
break;
case "3":
System.out.println("欢迎光临,下次再来!!");
System.exit(0);
}
}
}
}
用户类:
package User;
/**
* 需求:在该类中定义同户名个密码成员变量
* */
public class User {
private static String UserName;
private static String PassWord;
public User() {
super();
// TODO Auto-generatedconstructor stub
}
public static String getUserName() {
return UserName;
}
public void setUserName(String userName) {
UserName = userName;
}
public static String getPassWord() {
return PassWord;
}
public void setPassWord(String passWord) {
PassWord = passWord;
}
}
用户接口:
package UserDao;
import User.User;
/**
* 在该接口中定义两个抽象方法,模拟用户注册和登录
* */
public interface UserDao {
public abstract boolean IsLogin(String UserName,String PassWord);
public abstract void Rigest(User user);
}
接口的子实现类
package Impl;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import User.User;
import UserDao.UserDao;
public class UserImpl implements UserDao {
//创建FIle类的对象,用来封装数据源
public static File file=new File("User.txt");
static{
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("创建文件失败!");
// e.printStackTrace();
}
}
public boolean IsLogin(String UserName, String PassWord) {
boolean flag=false;
//需要从文件中读取数据,创建字符缓冲输入流
BufferedReader br=null;
try {
br=new BufferedReader(new FileReader(file));
String line=null;
while((line=br.readLine())!=null){
//使用注册时定义的规则来区分用户名和密码
String[] dates = line.split("=");
if(dates[0].endsWith(UserName) &&dates[1].endsWith(PassWord)){
flag=true;
}
}
} catch (FileNotFoundException e) {
System.out.println("没有找到指定的文件!");
// e.printStackTrace();
} catch (IOException e) {
System.out.println("用户登录失败!");
// e.printStackTrace();
}finally{
if(br!=null){
try {
br.close();
} catch (IOException e) {
System.out.println("登录失败!");
// e.printStackTrace();
}
}
}
return flag;
}
public void Rigest(User user) {
//需要创建字符缓冲输出流来向文件中写数据
BufferedWriter bw=null;
try {
bw=new BufferedWriter(new FileWriter(file,true));
//调用字符缓冲输出流的writer()方法向文件中写数据,同时指明一种格式
bw.write(User.getUserName() + "=" + User.getPassWord());
//刷新该流
bw.flush();
//调用该流类的特有方法写入换行符
bw.newLine();
} catch (IOException e) {
System.out.println("向文件中写数据失败!");
// e.printStackTrace();
}finally{//在该代码中关闭流资源
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
}
}
}
最后
以上就是孝顺便当为你收集整理的多线程三种实现方式/IO流模拟用户注册及登录的全部内容,希望文章能够帮你解决多线程三种实现方式/IO流模拟用户注册及登录所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复