1. java的基本程序设计结构
1.1 数据类型
java是一种强类型语言,必须为每一个变量声明一种类型。
在java中一共有8种基本类型:
类型 存储需求 取值范围
int 4字节 -2 147 483 648 ~ 2 147 483 647
short 2字节 -32 768 ~ 32 767
long 8字节 -9 233 372 036 854 775 808 ~ 9 233 372 036 854 775 807
byte 1字节 -128 ~ 127
float 4字节 大约 ±3.402 823 47E+38F(有效位为6~7位)
double 8字节 大约 ±1.797 693 134 862 315 70E+308
char
boolean
1.2 运算符
- && 逻辑与运算符:有0出0,全1出1
按照“短路”方式求值
expression1 && expression2
当第一个表达式的值为false,结果就不可能为true 则不需要计算第二个表达式 可以使用在:看做是第一个表达式成立的前提下,满足第二个表达式
- || 逻辑或运算符:有1出1,全0出0
expression1 && expression2
当第一个表达式的值为true,结果就为true 则不需要计算第二个表达式 可以使用在:不能确定第一个表达式成立时,增加另外一个必定成立的表达式二来保证整个判定为true
- 三目运算符 ?:
condition ? expression1 && expression2
当condition为true时,为第一个表达式的值,为false时,则计算第二个表达式的值
1.2.1 位运算符
处理整型类型时,可以直接对组成整型数值的各个位完成操作。
- 位运算符包括: &与 |或 ^非 ~取反
应用在布尔值上& |运算符也会得到一个布尔值,但是不采用短路的方式
- 位移运算:
<< 左移 不分正负 低位补0
以byte 8位为例:
正数: 20 << 2
补码:(正数的补码与原码反码相同)0001 0100
左移两位后: 0101 0000
result = 80
负数: -20 << 2
补码:(负数的反码:符号位不变,其余取反,补码为反码+1)1110 1100
左移两位后: 1011 0000
原码 :1101 0000
result = -80
>> 右移 如果符号位为0则补0 为1补1
正数: 20 >> 2
补码:0001 0100
右移两位后: 0000 0101
result = 5
负数: -20 >> 2
补码:1110 1100
右移两位后: 1111 1011
原码 :1000 0101
result = -5
>>> 右移 无符号右移(逻辑右移) 不管符号位为0还是1 右移都是高位补0
20 >>> 2
result = 5
-20 >>> 1
result = 5
1.3 代码块
- 静态代码块: 在类加载的时候就已经运行了,且只运行一次。当代码需要在项目启动时就执行,可以使用静态代码块 如:一个项目启动需要加载的很多配置文件等资源
- 构造代码块: 构造代码块在创建对象时被调用,每次创建对象都会调用一次 和构造方法的作用类似,都能对对象进行初始化,并且只要创建一个对象,构造代码块都会执行一次。但是反过来,构造函数则不一定每个对象建立时都执行(多个构造函数情况下,建立对象时传入的参数不同则初始化使用对应的构造函数)
- 构造方法: 方法名必须与类名相同且无返回值 多用于创建对象时定义初始化的状态
- 普通代码块: 定义在方法中的代码块
执行顺序:
public class Demo01 {
static {
System.out.println("执行静态代码块");
}
public demo01() {
System.out.println("执行构造方法");
}
{
System.out.println("执行构造代码块");
}
public void sss(){
{
System.out.println("执行普通代码块");
}
}
public static void main(String[] args) {
new demo01().sss();
}
}
1.4 字符串(String)
7. 并发
1. 什么是并发?
在学习操作系统中,并发是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
如:一边吃饭一边玩手机,在某一时刻大脑所做的事是唯一的,但在高速切换的时间非常短 让人感觉是在同时进行的
- 程序:是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体
- 进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位
进程是一个动态的实体,它有自己的生命周期。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消。反映了一个程序在一定的数据集上运行的全部动态过程。
- 线程:是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
2. java创建线程的三种方式
2.1 继承Thread类(不建议使用:避免OOP单继承局限性)
public class Test01 extends Thread{
@Override
public void run() {
//do some work
}
public static void main(String[] args) {
new Test01().start();
}
}
2.2 实现Runnable接口
public class Test01 {
@Override
public void run() {
//do some work
}
public static void main(String[] args) {
Runnable t1 = new Test01();
new Thread(t1).start();
}
}
2.3 实现callable接口
@Override
public Boolean call() throws Exception {
//do some work
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Test03 t1 = new Test03();
Test03 t2 = new Test03();
Test03 t3 = new Test03();
//创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> result1 = ser.submit(t1);
Future<Boolean> result2 = ser.submit(t2);
Future<Boolean> result3 = ser.submit(t3);
//获取结果
boolean r1 = result1.get();
boolean r2 = result1.get();
boolean r3 = result1.get();
//关闭服务
ser.shutdownNow();
}
}
3. 龟兔赛跑模拟程序并发问题
//模拟龟兔赛跑
public class Race implements Runnable{
//获胜者
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
if (Thread.currentThread().getName().equals("兔子")){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判断比赛是否结束
if (iswiner(i)){
break;
}
System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
}
}
//判断是否完成比赛
public Boolean iswiner(int steps){
//判断是否有胜利者
if(winner != null){// 已经存在胜利者
return true;
}else {
if (steps == 100){
winner = Thread.currentThread().getName();
System.out.println("winner is "+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
new Thread(new Race(),"乌龟").start();
new Thread(new Race(),"兔子").start();
}
}
4. 线程状态
4.1 停止线程
//1.建议线程正常停止--》利用次数,不建议死循环
//2.建议使用标志位--》设置一个标志位
public class Test04 implements Runnable{
//1.设置一个标志位
private boolean flag = true;
@Override
public void run() {
while (flag){
//do some work
}
}
//设置一个公开发方法停止线程,装换标志位
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
Test04 t1 = new Test04();
new Thread(t1).start();
for (int i = 0; i < 100; i++) {
if (i == 90){
//调用stop方法切换标志位,停止线程
t1.stop();
}
}
}
}
4.2 线程休眠(进入阻塞状态)
4.3 线程礼让
4.4 Join
public class TestJoin implements Runnable{
@Override
public void run() {
//do some work
System.out.println("插队");
}
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 100; i++) {
if (i == 20){
thread.join();
}
}
}
}
5 线程状态观测
//观察测试线程的状态
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 2; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("////////");
});
//观察状态
Thread.State state = t1.getState();
System.out.println(state);
//观察启动后
t1.start();
state = t1.getState();
System.out.println(state);
while (state != Thread.State.TERMINATED){//线程不终止时
Thread.sleep(500);
state = t1.getState();
System.out.println(state);
}
}
}
5.1 线程的优先级
public class TestPriority {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
Mypriority mypriority = new Mypriority();
Thread t1 = new Thread(mypriority);
Thread t2 = new Thread(mypriority);
Thread t3 = new Thread(mypriority);
Thread t4 = new Thread(mypriority);
//先设置优先级 再启动
t1.setPriority(1);
t1.start();
t2.setPriority(5);
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);
t3.start();
t4.setPriority(8);
t4.start();
}
}
class Mypriority implements Runnable{
@Override
public void run() {
//do some work
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
5.2 守护线程
//测试守护线程
//上帝守护着你
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
People people = new People();
Thread thread = new Thread(god);
thread.setDaemon(true); //默认false是用户线程,正常都是用户线程
//上帝线程启动
thread.start();
new Thread(people).start();
}
}
class God implements Runnable{
@Override
public void run() {
while (true){
System.out.println("上帝守护着你");
}
}
}
class People implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("每一天都在开心的活着");
}
System.out.println("======= GoodBye World! ========");
}
}
6. 线程同步
处理多线程问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象,这时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要访问此对象的线程进入这个 对象的等待池 形成队列,等待前一个线程使用结束,再执行下一个线程
6.1 队列和锁
6.2 线程不安全例子
- 不安全的买票
//不安全的买票
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"子船").start();
new Thread(buyTicket,"微微").start();
new Thread(buyTicket,"锶婷").start();
}
}
class BuyTicket implements Runnable{
//票
int ticketNum = 10;
boolean falg = true; //外部停止方式
@Override
public void run() {
//买票
while (falg){
buy();
}
}
private void buy(){
//判断是否有票
if (ticketNum <= 0){
falg = false;
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到"+ticketNum--);
}
}
- 银行不安全的取钱
//不安全的取钱
//两个人去银行取钱,账户
public class UnsafeBank {
public static void main(String[] args) {
//账户
Account account = new Account(100, "旅游基金");
Drawing zc = new Drawing(account, 50, "子船");
Drawing ww = new Drawing(account, 100, "微微");
zc.start();
ww.start();
}
}
//账户
class Account{
int money; //余额
String name; //卡名
public Account(int money,String name){
this.money = money;
this.name = name;
}
}
//银行,模拟取钱
class Drawing extends Thread{
Account account;// 账户
//取了多少钱
int darwingMoney;
//现在有多少钱
int nowMoney;
public Drawing(Account account,int darwingMoney,String name){
super(name);
this.account = account;
this.darwingMoney = darwingMoney;
}
//取钱
@Override
public void run() {
if (account.money - darwingMoney < 0){
System.out.println(Thread.currentThread().getName()+"余额不足");
return;
}
//余额 = 余额 - 取出的钱
account.money = account.money - darwingMoney;
//xx宝的钱 = 原来的钱 + 取出的钱
nowMoney = nowMoney + darwingMoney;
System.out.println(account.name+",您的账户余额为"+account.money);
System.out.println(this.getName()+"xx宝余额为"+nowMoney);
}
}
- 线程不安全的集合
//线程不安全的集合
public class UnsafeList {
public static void main(String[] args){
List list = new ArrayList();
for (int i = 0; i < 1000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
两个线程同一时间操作数组的同一位置 导致数据覆盖了
6.3 同步方法和同步块 synchronize
例子一的解决方法 在方法上加synchronize变成同步方法
private synchronized void buy(){
例子二的解决方法 synchronize同步块锁定account对象
synchronized (account){
//先判断账户有没有钱
if (account.money - darwingMoney < 0){
System.out.println(Thread.currentThread().getName()+"余额不足");
return;
}
//余额 = 余额 - 取出的钱
account.money = account.money - darwingMoney;
//xx宝的钱 = 原来的钱 + 取出的钱
nowMoney = nowMoney + darwingMoney;
System.out.println(account.name+",您的账户余额为"+account.money);
System.out.println(this.getName()+"xx宝余额为"+nowMoney);
}
例子三的解决方法
new Thread(()->{
synchronized (list){
list.add(Thread.currentThread().getName());
}
}).start();
7. 死锁
//两个线程互相拥有对象需要的资源,而各自等待造成程序死锁
public class Deadlock {
public static void main(String[] args) {
Makeup makeup = new Makeup(0, "白雪公主");
Makeup makeup1 = new Makeup(1, "睡美人");
makeup.start();
makeup1.start();
}
}
//口红
class Lipstick{
}
//镜子
class Mirror{
}
class Makeup extends Thread {
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;//选择
String girlName;//化妆的人
public Makeup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妆
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) { //获得口红的锁
System.out.println(this.girlName + "获得口红的锁");
Thread.sleep(1000);
synchronized (mirror) { //一秒后想获得镜子
System.out.println(this.girlName + "获得镜子的锁");
}
}
} else {
synchronized (mirror) { //获得镜子的锁
System.out.println(this.girlName + "获得镜子的锁");
Thread.sleep(1000);
synchronized (lipstick) { //一秒后想获得口红
System.out.println(this.girlName + "获得口红的锁");
}
}
}
}
}
程序一直死锁 停止在这
7.1 Lock
class BuyTicket implements Runnable{
//票
int ticketNum = 10;
private static ReentrantLock lock = new ReentrantLock();
boolean falg = true; //外部停止方式
@Override
public void run() {
//买票
while (falg){
try{
lock.lock();
buy();
}finally {
//解锁
lock.unlock();
}
}
}