Java重点--多线程
目录
引入
一段代码:
内存图:
Final
⭐并发(多个线程对同一个资源进行访问使用)
=======代码===部分======
一个输出日历的类
结果:
一个常用的Java:
构造器
什么是封装:
引入
线程的几种状态:新建--就绪--运行--死亡--阻塞--等待---睡眠
一段代码:
package 数据结构;
public class Text {
public static void main(String[] mmm) {
// 新建--就绪--运行--死亡--阻塞--等待---睡眠
Thread x1=new Thread() {
@Override //重写run方法
public void run() {
for(;;) {
System.out.println("======");
}
}
};
Thread x2=new Thread() {
@Override //重写run方法
public void run() {
for(;;) {
System.out.println("#####");
}
}
};
x1.start();//进入就绪态,并不是立即执行(但是因为在操作系统中,和人交互的线程优先级最高,如键盘鼠标等输入输出的操作,所以达到了看似立即执行的效果)
//操作系统能调度的任务只能是就绪态的
x2.start();
for(;;) {
System.out.println("%%%%");
}
}
}
//多线程
内存图:
- 操作系统进行任务的统一调度,使CPU核心轮流执行(即核心也受操作系统调度);
- 控制硬件必须通过驱动,而驱动必须受操作系统调度;
- 线程优先级:如果因为高优先级的线程夺走了CPU,那么在高优先级线程执行结束后,会根据时间片记录的位置重新回到被剥夺线程进行调度运行。
- 线程被分配的时间片是随机的,如果一个1ms就能执行结束的线程被分配了8ms时间片,那么剩余的7ms就会立即释放CPU,并分配给其他线程;如果一个8ms的线程被分配了1ms的时间片,那么时间片就会记录该线程调度的位置,等下次CPU得到时间片后,就会从上次执行剩余的开始位置7ms位置开始运行。
- 像QQ、微信这种能一直进行,是因为里面有个死循环,没有被打破,所以会一直处于运行待机状态。
start()会将线程存在操作系统的就绪队列
多线程就是开了多个栈,并行(执行结束后,子线程会结束死亡,只剩下主线程存活):
堆中创建的对象,线程可以直接访问(因为进程是资源分配的最小单位-->而进程中的线程可以共享资源)
【补】线程是资源调度的最小单位,线程是进程中的基本单位(进程由线程组成)
⭐被final修饰的单元素变量不可以修改;引用类型不能更改指向(可以改变里面的值,不可以改变指向)
类似:线程调用公共资源时,子线程不能修改int等类型的单类型数据;int[]等类型的引用类型不能修改其指向(能修改其值);String字符串则不能被修改(因为字符串是不可变类型,想修改只能通过修改字符串常量池的指向,而且又因为String是引用类型,不能被修改指向,所以就不能修改了)
Final
final不修饰复杂的引用类型,因为它拦不住复杂引用类型属性的变化,所以通常final用来修饰基本类型和String类型。
【如下:final经常配合static配合使用,即静态常量】
======
线程创建完毕后就没有依赖关系了,所以Java中线程之间没有先后顺序,只有在同一线程内,才有顺序之分。
⭐并发(多个线程对同一个资源进行访问使用)
如下:
最终输出可能是?
结果是:0;
因为start()只是将x1,x2调为就绪态,又因为print是用户操作,所以很可能x1,x2还没来得及执行,就已经输出a[0]了。
解决(如下):
x1.join()功能就是要等x1执行完;同理加上x2.join(),就可以解决上面问题了
=======代码===部分======
一个输出日历的类
package 数据结构;
import java.time.DayOfWeek;
import java.time.LocalDate;
public class CalendarTest {
public static void main(String[] args) {
LocalDate date=LocalDate.now();
int month=date.getMonthValue();
int today=date.getDayOfMonth();
date=date.minusDays(today-1);
DayOfWeek weekday=date.getDayOfWeek();
int value=weekday.getValue();
System.out.println("Mon Tue Wed Thu Fri Sat Sun");
for(int i=1;i<value;i++) {
System.out.print(" ");
while(date.getMonthValue()==month) {
System.out.printf("%3d",date.getDayOfMonth());
if(date.getDayOfMonth()==today) {
System.out.print("*");
}else {
System.out.print(" ");
}
date=date.plusDays(1);
if(date.getDayOfWeek().getValue()==1) {
System.out.println();
}
}
if(date.getDayOfWeek().getValue()!=1) {
System.out.println();
}
}
}
}
结果:
一个常用的Java:
【一个class里面可以有多个类,但是只能有一个public类型的】
一个类:
package 数据结构;
import java.time.LocalDate;
public class Employee {
private String name;
private double salary;
private LocalDate hireDay;
//构造器
public Employee(String n,double s,int year,int month,int day) {
name=n;
salary=s;
hireDay=LocalDate.of(year, month, day);
}
//访问器*4(下面)
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public LocalDate getHireDay() {
return hireDay;
}
public void raiseSalary(double byPercent) {
double raise=salary*byPercent/100;
salary+=raise;
}
}
【另一种表达方式:】
{类似于js里面的this方法,哪个对象调用,就表示谁}
Main函数
package 数据结构;
import javax.print.attribute.standard.MediaName;
public class EmployeeTest {
public static void main(String[] args) {
Employee[] staff=new Employee[3];
staff[0]=new Employee("x1", 75000, 1989, 12, 22);
staff[1]=new Employee("x3", 76000, 1939, 10, 12);
staff[2]=new Employee("x5", 89000, 1984, 11, 2);
for(Employee e:staff) {
e.raiseSalary(5);
}
for(Employee e:staff) {
System.out.println("name="+e.getName()+",salary="+e.getSalary()+",hireDay="+e.getHireDay());
}
}
}
构造器
什么是封装:
只需要照着说明调用就好,不需要了解底层逻辑。
域就是属性,属性就是域(域.属性就是除却方法外的那些,属于大类的特性e.g .age,.name)