Java10
- (一)、配置文件
- (二)、多线程
- 2.1 并发和并行
- 2.2 多线程的实现方式
- 2.3 常见成员方法
- 2.3.1 线程的优先级
- 2.3.2 守护线程(备胎线程)
- 2.3.3 礼让线程和插入线程
- 2.4 线程生命周期
- 2.4 线程安全问题
- 2.5 锁
- 2.5.1 死锁
(一)、配置文件
好处:
1.可以把软件的设置永久化存储
2.如果我们要修改参数,不需要改动代码,直接修改配置文件就行
properties配置文件:
后缀名就是properties
文件中数据都是按照键值对存储
可以往Properties添加任意类型数据,但是一般只添加string类型数据
特有方法:store和load
load(加载):把本地文件数据加载进程序中
store(保存):把数据写进本地文件
(二)、多线程
多线程可以让程序同时做多件事情,提高运行效率
线程:操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位(应用软件中相互独立,可以同时运行的功能)
进程:是程序的基本执行实体 (一个软件运行之后就是一个进程)
2.1 并发和并行
并发:同一时刻,多个指令在单个cpu上交替执行
并行:同一时刻,多个指令在多个cpu上同时执行
2.2 多线程的实现方式
1.继承Thread类的方式进行实现
测试类:
package dxc;
public class d1 {
public static void main(String[] args) {
/*
* 多线程的第一种启动方式:
* 1.定义一个类继承Thread
* 2.重写run方法
* 3.创建子类的对象,并启动线程
*
* */
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
//交替运行
}
}
MyThread:
package dxc;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i <100 ; i++) {
System.out.println(getName()+"HelloWorld");
}
}
}
2.实现Runnable接口的方式进行实现
测试类:
package dxc;
public class d2 {
public static void main(String[] args) {
/*
* 1.自己定义一个类实现Runnable接口
* 2.重写里面的run方法
* 3.创建自己的类的对象
* 4.创建一个Thread类的对象,并开启线程
* */
//创建MyRun对象,表示多线程要执行的任务
MyRun mr=new MyRun();
//创建线程对象
Thread t1=new Thread(mr);//将要执行的任务放进去
Thread t2=new Thread(mr);
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();//交替执行
}
}
MyRun:
package dxc;
public class MyRun implements Runnable{
@Override
public void run() {
//书写线程要执行的代码
for (int i = 0; i < 100; i++) {
//获取到当前线程的对象
Thread t = Thread.currentThread();
System.out.println(t.getName()+"HelloWorld");
}
}
}
3.利用Callable接口和Future接口方式实现
测试类:
package dxc;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class d3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
* 特点:可以获取多线程运行的结果
*
* 1.创建一个类MyCallable实现Callable接口
* 2.重写call(有返回值,表示多线程运行结果)
* 3.创建MyCallable的对象(表示多线程要执行的任务)
* 4.创建FutureTask对象(管理多线程运行的结果)
* 5.创建Thread类的对象,并启动(表示线程)
* */
MyCallable mc=new MyCallable();
FutureTask<Integer> ft=new FutureTask<>(mc);
Thread t1=new Thread(ft);
t1.start();
Integer result = ft.get();
System.out.println(result);
}
}
MyCallable:
package dxc;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
return sum;
}
}
三种实现方式优缺点:
2.3 常见成员方法
注:
如果不给线程设置名字,线程有默认名字
格式:Thread-x(x从0开始)
Thread构造方法可以传递一个字符串,直接设置线程名字
JVM虚拟机启动后,会自动启动多条线程,
其中一条线程叫main线程,作用是调用main方法,并执行里面的代码
sleep():哪条线程执行到这个方法,这条线程就会在这里停留对应的时间
方法的参数就是停留的时间,毫秒。时间到了后,线程会自动醒来,继续执行下面其他代码
2.3.1 线程的优先级
Java中线程是抢占式调度(随机)
默认线程优先级是5
优先级:1-10(1最小)
优先级高,只是抢占cpu概率大,先执行完的概率大,但并非100%抢占
2.3.2 守护线程(备胎线程)
当其他非守护线程执行完毕之后,守护线程也会陆续执行完毕
2.3.3 礼让线程和插入线程
礼让线程:出让cpu的执行权
用在run方法中,尽可能让执行结果均匀
插入线程:
package dxc;
public class d5 {
public static void main(String[] args) throws InterruptedException {
MyThread t=new MyThread();
t.setName("土豆");
t.start();
//表示把t这个线程插入到当前线程之前
//t:土豆
//当前线程:main线程
t.join();
//执行在main线程当中的
for (int i = 0; i < 10; i++) {
System.out.println("main线程"+i);
}
}
}
2.4 线程生命周期
sleep结束后,是不会立即执行下方代码的,要等抢到执行权
2.4 线程安全问题
线程执行有随机性。产生如数据越界,重复等等问题
同步代码块:
把操作共享数据的代码锁起来
格式:
锁对象可以是任意的,但是锁对象一定是唯一的
特点1:锁默认打开,有一个线程进去了,锁自动关上
特点2:当里面所有代码执行完毕,线程出来,锁自动打开
注:同步代码块不能写在循环的外面
锁对象可以使用当前类的字节码文件对象。类名.class
同步方法:把synchronized加在方法上,写在修饰符后面
特点:1.同步方法是锁住方法里面所有的代码
2.锁对象不能自己指定:非静态方法:this。静态方法:当前类的字节码文件对象
StringBuffer用于多线程安全中
需求:100个票,三个窗口卖票
package dxDemo;
public class MyRunnable implements Runnable{
int ticket=0;
@Override
public void run() {
//1.循环
//2.同步代码块(同步方法)
//3.判断共享数据是否到了末尾
while (true){
if (method()) break;
}
}
private synchronized boolean method(){
if (ticket==100){
return true;
}else {
ticket++;
System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");
}
return false;
}
}
test:
package dxDemo;
public class test {
public static void main(String[] args) {
MyRunnable mr=new MyRunnable();
Thread t1=new Thread(mr);
Thread t2=new Thread(mr);
Thread t3=new Thread(mr);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
2.5 锁
手动上锁和释放锁:
void lock():获得锁
void unlock():释放锁
卖票代码改成手动锁
package dxDemo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyRunnable implements Runnable{
static int ticket=0;
static Lock lock=new ReentrantLock();
@Override
public void run() {
//1.循环
//2.同步代码块(同步方法)
//3.判断共享数据是否到了末尾
while (true){
lock.lock();
try {
if (ticket==100){
break;
}else {
Thread.sleep(10);
ticket++;
System.out.println(Thread.currentThread().getName()+"在卖第"+ticket+"张票");
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
}
}
2.5.1 死锁
是一种错误(一个线程拿a锁,一个拿b锁,都在等对方解锁)
不要让锁嵌套,容易造成死锁,使代码卡死