1. Properties的使用、 属性文件:
properties(用于存放键值对数据的一种文件类型)
-
测试
// Properties --属性﹐对应一种文件格式 //xx. properties文件,叫属性文件。 // **文件内容格式: key=value ,等号前面是键﹐等号后面是值。一个键值对是一行。 public class TestProperties { public static void main(String[] args) throws IOException { // 1.创建对象 Properties p = new Properties(); // 2.添加数据 p.setProperty("yw", "100"); p.setProperty("sx", "90"); // 3.取出数据 System.out.println(p.getProperty("yw")); System.out.println(p.getProperty("sx")); // 4.通过io流,加载一个本地属性文件﹐把文件内容保存Properties对象中。 System.out.println("--------a.properties-----"); FileInputStream fis = new FileInputStream("E:\\Desktop\\Games\\HQYJ\\Projects\\javase\\src\\day7\\a.properties"); Properties p1 = new Properties(); p1.load(fis); Set<Map.Entry<Object, Object>> entries = p1.entrySet(); entries.forEach(System.out::println); System.out.println("根据key找value: " + p1.get("username")); } }
-
属性文件:a.properties
yw=100 sx=90 yy=80 hx=70 username=root1 password=123456 port=3306 dbname=crm
2. 线程
1. 什么是线程
- java程序支持多线程,并且java中的多线程处理较为简单。一般操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序被称为进程,当程序运行时候,内部可能包含多个顺序流执行,每个顺序执行流就是一个线程。
2. 线程类型
- Thread类代表线程类型
- 任何线程对象都是Thread类(子类)的实例
- Thread类是线程的模板(封装了复杂的线程开启等操作,封装了操作系统的差异性等)
- 只要重写run方法,就可以实现具体线程。
3. 具体实现
1 . 继承Thread类
-
创建一个类,继承Thread类
-
重写run方法,实现用户字自己的过程
-
创建线程实例(即子类的对象) ,通过start方法,启动线程,线程启动之后,会尽快执行run方法
-
测试
public class ThreadDemo2 { public static void main(String[] args) throws InterruptedException { //创建对象 MyThread t1 = new MyThread(); AnthorThread t2 = new AnthorThread(); //设置线程优先级 t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MIN_PRIORITY); //启动线程 : 调用start方法,启动了线程。然后线程会自动调用自己的run方法。 t1.start(); // 表示线程进入到:runnable状态,即可运行状态。 这个时候如果cpu分配了时间片,然后线程就调用run方法。 t2.start(); Thread.sleep(3000); // main对应的线程等待3秒。 System.out.println(t1.isAlive()); System.out.println(t2.isAlive()); } } /*public class Thread implements Runnable {}*/ class MyThread extends Thread { //通过重写run方法,设置线程的功能。 @Override public void run() { System.out.println("hello Thread"); } } class AnthorThread extends Thread { @Override public void run() { System.out.println("你好, 世界"); } }
2. 通过使用Runnable接口,创建线程
-
创建一个类,实现Runnable接口, 重写run 方法
-
以实现了Runnable接口的类的实例,作为创建Thread类的参数。
-
测试
//定义三个线程关型 //**第一个每隔500毫秒,说一句:要下课了,重复500次 // 第二个每隔300毫秒,说一句:中午吃什么,重复500次 // 第三个每隔100毫秒:说一句:写作业,重复500次 //Thread . sleep(时间) --等待多久。 //最后观察程序执行过程。 public class ThreadDemo3_1 { public static void main(String[] args) { B b = new B(); Thread t = new Thread(b); t.start(); //启动线程类 //System.out.println(b); //Date d = new Date(System.currentTimeMillis()); //System.out.println(d); //使用匿名内部类 Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i =0; i < 50; i++){ System.out.println("要下课了"); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } }); t1.start(); Thread t2 = new Thread(() -> { for (int i = 0; i < 50; i++) { System.out.println("中午吃什么"); try { Thread.sleep(30); } catch (InterruptedException e) { e.printStackTrace(); } } }); t2.start(); Thread t3 = new Thread(() -> { for (int i = 0; i < 50; i++) { System.out.println("写作业"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }); t3.start(); } } //创建自己的线程 //①extends 继承Thread //② 写一个类,实现Runnable接口 class A{ void print(){ System.out.println("Hello"); } } //实现了Runnable接口, 不能说B是线程类 class B extends A implements Runnable{ //int k; //什么时候能用? void print(){ System.out.println("Hello"); } @Override public void run() { Thread t = Thread.currentThread(); // 获取当前线程 System.out.println(t.getName() + "--------" + t.getId()); //计算出1~100的和 int sum = 0; for(int i = 1; i <= 100; i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } sum += i; } //this.k = sum; System.out.println("和:" + sum); } }
3. Callable接口
-
测试
import java.util.concurrent.Callable; //接口 import java.util.concurrent.ExecutorService; //接口 import java.util.concurrent.Executors; //工具类 import java.util.concurrent.Executor;// 接口 import java.util.concurrent.ThreadPoolExecutor; //实现类 //ThreadPool : 线程池 public class ThreadPoolDemo { public static void main(String[] args) { //*** newFixedThreadPool -- 创建固定个数的线程池 ExecutorService es = Executors.newFixedThreadPool(2); //参数是Runnable es.submit(() -> { Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "----" + thread.getId()); for (int i = 0; i < 10; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----------1-------------"); } }); //参数是Callable es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "----" + thread.getId()); for (int i = 0; i < 10; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----------2-------------"); } return 100; } }); //参数是Callable es.submit(() -> { // lambda 表达式 Thread thread = Thread.currentThread(); System.out.println(thread.getName() + "----" + thread.getId()); for (int i = 0; i < 10; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----------3-------------"); } return 100; }); es.shutdown(); // 关闭线程池 } }
4. 守护线程
-
守护线程是指在线程运行前,将线程设置为守护线程,那么当程序中没有其他线程运行时候,jvm退出,程序就终止。
-
测试
// 守护线程 public class ThreadDemo4 { public static void main(String[] args) { Thread t1 = new Thread(() -> { // 每隔10毫秒输出:"xxxxxxxx" for (int i = 0; i < 100; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("介绍xx产品:......." + i); } }); t1.start(); Thread t2 = new Thread(() -> { // 每隔10毫秒输出:"xxxxxxxx" for (int i = 0; i < 1000; i++) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("刷了一个轮船......." + i); } }); t2.setDaemon(true); // 启动之前,设置其为守护线程。 t2.start(); } }
5. 线程对象的方法
-
//** java支持多线程:多个程序干不同的事情. 怎么创建多个线程 //** 之前的程序中,没有创建出多线程对象,那么就只有一个线程(main方法对应的线程)在工作:单线程程序 public class ThreadDemo { public static void main(String[] args) { //获取当前线程 Thread thread = Thread.currentThread(); // main方法对应的线程 //线程di System.out.println(thread.isDaemon()); //每个线程有一个唯一的id //线程名字 System.out.println(thread.getName()); //线程的优先级 System.out.println(thread.getPriority());//优先级高的线程,cpu分配的时间片就多,优先运行。 //线程的状态 System.out.println(thread.getState()); //是否活着 System.out.println(thread.isAlive()); // RUNNABLE 可运行的 //是否为守护线程(精灵线程):被守护的线程结束了,守护线程也就结束了 System.out.println(thread.isDaemon()); } }
6. 线程的状态
7. sleep方法
- Thread.sleep(times) 使当前线程从running放弃处理器,进入block状态,休眠times毫秒,再进入runnable状态。
8. 线程同步
- 异步: 并发,线程间互不影响,自己干自己的。
-
测试
import java.util.Date; public class SynchronizedDemo1 { public static void main(String[] args) { //记录程序开始时间,记录每个线程结束的时间(最后的结束时间,就是整个程序运行的结束时间 System.out.println("线程结束:" + new Date()); // main方法对应的主线程 Thread t1 = new Thread(() -> { add("小红"); //System.out.println("线程结束:" + new Date(System.currentTimeMillis())); 由于Date的空参构造函数的返回值为: this(System.currentTimeMillis()); System.out.println("线程结束:" + new Date()); }); Thread t2 = new Thread(() -> { add("小黄"); System.out.println("线程结束:" + new Date()); }); Thread t3 = new Thread(() -> { add("小名"); System.out.println("线程结束:" + new Date()); }); t1.start();t2.start();t3.start();//线程的并发 } public static void add(String str) { //方法没有上锁,异步 try { Thread.sleep(5000); //等5秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello:" + str); } }
-
所谓同步,就是指在调用某个功能的时候,在没有得到结果之前,该调用不返回,同时其他线程无法使用这个功能。步调一致的处理,有序地执行。
-
多个线程并发读写同一个临界资源的时候,会发生“线程并发安全问题”,使用同步代码块,解决并发安全问题.
-
synchronized可以修饰方法,表示整个方法修的全部内容需要同步。
synchronized(同步监视器){ // … } ,
同步监视器一般是一个对象。尽量减小同步范围,提高并发的效率。 -
测试
import java.util.Date; public class SynchronizedDemo2 { public static void main(String[] args) { //记录程序开始时间,记录每个线程结束的时间(最后的结束时间,就是整个程序运行的结束时间 System.out.println("线程结束:" + new Date()); // main方法对应的主线程 Thread t1 = new Thread(() -> { add("小红"); System.out.println("线程结束:" + new Date()); }); Thread t2 = new Thread(() -> { add("小黄"); System.out.println("线程结束:" + new Date()); }); Thread t3 = new Thread(() -> { add("小名"); System.out.println("线程结束:" + new Date()); }); t1.start();t2.start();t3.start();//线程的并发 } public static void add(String str) { //方法上锁,同步 try { Thread.sleep(5000); //等5秒 } catch (InterruptedException e) { e.printStackTrace(); } /* synchronized(this){ for (int i = 0; i < 100; i++) { System.out.println("Hello:" + str); } } */ } }
-
3. Socket编程
CS架构:
-
在C/S模式下,客户向服务器端发出请求,服务器端接收到请求之后,提供相应的服务。
-
客户端部分: 每个用户都有自己的客户端,负责发送请求。
-
服务端部分: 多个用户共享一个服务器,处理每个客户端的请求。
-
ServerSocket & Socket
-
测试
-
Server
//服务器端的程序 public class Server { private ServerSocket server; //构造函数: 初始化成员变量 public Server() { System.out.println("开始初始化...."); try { // 端口号。程序启动的时候,会占用一个端口号, // 通过端口号找到对应的程序 server = new ServerSocket(9999); } catch (IOException e) { e.printStackTrace(); } System.out.println("初始化完成...."); } //启动服务器: 等待客户端连接,然后给客户提供服务。 public void start() throws IOException { while (true) { System.out.println("等待客户端连接...."); //这个引用指向的就是当前连接上的客户端的Socket Socket client = server.accept(); InetAddress inetAddress = client.getInetAddress(); String ip = inetAddress.getHostAddress(); int port = client.getPort(); System.out.println(ip + "---" + port + "连接成功"); //io操作 -- 服务器接受消息 InputStream in = client.getInputStream(); InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); String word = br.readLine(); System.out.println(ip + ":" + port + "说:" + word); } } public static void main(String[] args) throws IOException { //创建服务器端 Server s = new Server(); s.start(); } }
-
Client
//客户端的程序 public class Client { private Socket socket; public Client(){ System.out.println("开始连接服务器...."); try { //host:主机 //port:端口 //localhost:特殊的字符串,代表的就是你的电脑的域名 //127.0.0.1: 特殊的ip, 代表的就是你电脑的ip //new Socket:是为了找到主机上的某个软件。 //要找的服务器软件就在这个电脑上,所以使用localhost //要找的主机上的软件的端口号是9999 socket = new Socket("localhost",9999); } catch (IOException e) { e.printStackTrace(); } System.out.println("连接服务器成功...."); } //启动客户端 public void start() throws IOException { //io操作 -- 客户端给服务器发消息 OutputStream out = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(out); BufferedWriter bw = new BufferedWriter(osw); bw.write("你好服务器,我叫小红。"); bw.flush(); bw.close(); } public static void main(String[] args) throws IOException { //创建客户端 Client c = new Client(); c.start(); } }
-
4. review
1. 线程的创建方式有哪些?
-
继承Thread类:通过创建一个继承自Thread类的子类,然后重写**run()**方法来定义线程要执行的任务。
-
实现Runnable接口:通过实现Runnable接口,重写run()方法,然后将实现了Runnable接口的对象传递给Thread类的构造函数。
-
实现Callable接口:通过实现Callable接口,重写call()方法,然后将实现了Callable接口的对象传递给Thread类的构造函数。它允许线程执行任务并返回结果,同时也支持抛出异常。
2. Runnable 接口和 Callable接口的区别?
- 返回值:
- Runnable接口的**run()**方法没有返回值,因此任务执行后无法获取任务的执行结果
- Callable接口的**call()**方法可以返回一个结果,可以是任何类型。
- 异常抛出:
- **run()**方法不能直接抛出受检查的异常,但可以通过在方法内部捕获异常。
- **call()**方法可以抛出受检查的异常,因为它允许使用者捕获异常并处理。
- 使用方式:
- Runnable通常与Thread或者线程池结合使用,用于执行异步任务,但不关心任务的返回值。
- Callable通常与ExecutorService结合使用,允许获取线程任务的返回值,并能处理任务抛出的异常
- 灵活性:
- 由于Runnable没有返回值,它更适合简单的线程任务,不需要返回结果的情况。
- Callable提供了更大的灵活性,以为它允许返回结果并处理异常,适用与需要详细控制任务执行和获取结果的情况。
- Java版本:
- Runnable接口在较早的Java版本中就已经存在,而Callable接口是在Java5中引入的,作为并发包的一部分。
在选择使用Runnable还是Callable时,你可以根据任务的的性质和需求来决定。如果你需要执行简单的异步任务而不需要返回结果,那么使用Runnable更为合适。如果你需要获取任务的结果,处理异常,或者需要更大的灵活性,那么使用Callable会更好。